Member check exists, possibly in base class, version VS2005 / 08

In Member validation exists, possibly in the base class, version C ++ 11 , we developed a version of the classic C ++ 11 member validation type -trait from SFINAE to validate inherited member functions , which also works with C ++ 11 classes final

, but uses C ++ 11 features (namely decltype

) too:

template<typename T>
class has_resize_method {
    struct Yes { char unused[1]; };
    struct No { char unused[2]; };
    static_assert(sizeof(Yes) != sizeof(No));

    template<class C>
    static decltype(std::declval<C>().resize(10), Yes()) test(int);
    template<class C>
    static No test(...);
public:
    static const bool value = (sizeof(test<T>(0)) == sizeof(Yes));
};

      

MSVC has final

a non-standard extension named sealed

from VS2005, but decltype

only added in VS2010. This leaves VS2005 and 2008 where the class marked as sealed

still breaks the classic type-character and the C ++ 11 version cannot be used.

So, is there a way to formulate has_resize_method

so that it works with VC2005 / 08 classes too sealed

?

Obviously using C ++ 11 features to work with C ++ 11 ( final

) only problem is fine, so using VS-only extensions to work with VS2005 / 08 is only a class issue sealed

, but if there is a solution that works for all three sets compilers {C ++ 11, {VS2005, VS2008}, everyone else}, that would be cool, but probably too many to ask :)

+3


source to share


2 answers


I was able to find a solution that works in all major compilers. Unfortunately there is a preprocessor check for MSVC because it complains about a solution for other compilers. The main difference is that MSVC does not accept function pointers inside sizeof (), and conversely, GCC does not seem to accept (&C::resize == 0)

in check. Klang happily accepts both.

#include <iostream>

class Base  {
public:
    void resize(int, int, int) { }
};

class Derived : public Base {

};

class Unrelated  { };

template<typename T>
class has_resize_method {
    struct Yes { char unused[1]; };
    struct No { char unused[2]; };

#ifdef _MSC_VER
    template <class C>
    static Yes test(char (*)[(&C::resize == 0) + 1]);
#else
    template <class C>
    static Yes test(char (*)[sizeof(&C::resize) + 1]);
#endif
    template<class C>
    static No test(...);
public:
    static const bool value = (sizeof(test<T>(0)) == sizeof(Yes));
};

int main()  {
    std::cout << (has_resize_method<Base>::value ? "Base has method resize" : "Base has NO method resize") << std::endl;
    std::cout << (has_resize_method<Derived>::value ? "Derived has method resize" : "Derived has NO method resize") << std::endl;
    std::cout << (has_resize_method<Unrelated>::value ? "Unrelated has method resize" : "Unrelated has NO method resize") << std::endl;
    return 0;
}

      

Output:

Base has method resize
Derived has method resize
Unrelated has NO method resize

      



Tested on GCC 4.5.3, GCC 4.3.4, Clang 3.0, Visual C ++ 2008 and Visual C ++ 2010. I don't have access to Visual C ++ 2005, but I think it will work too. It also compiles on Comeau Online , but I cannot guarantee that it produces correct output there.

Works with both final and __- class.

Note that it checks not only member functions, but member pointers in general. You might want to add additional checks, such as boost::is_member_function_pointer

if this behavior is undesirable. Likewise, you can add checks for the number of arguments / argument types / result types - again, boost will be very useful here, especially. decomposition of type boost .

+4


source


MSVC has a special instruction __ if_exists with vs2005. MSDN link here . You can use it to directly control the name of a member function. And then check the signature. Below is a simple example of detecting foo:



template <typename T, typename U>
int8_t FooCheck( void(T::*)(U) )
{
    return 0;
}

template <typename T>
int16_t FooCheck( void(T::*)(double))
{
    return 0;
}

template <typename T>
int32_t FooCheck(void(T::*)(int))
{
    return 0;
}


template <typename T>
class Detector
{
public:

    __if_exists(T::foo)
    {    
       enum
       {
           value = sizeof(FooCheck(&T::foo))
       };
    }
    __if_not_exists(T::foo)
    {
       enum
       {
           value = 0
       };
   }

};


std::cout << Detector<Class>::value << std::endl;

      

+2


source







All Articles