正在检查成员是否存在,可能存在于基类VS2005/08版本中

Checking a member exists, possibly in a base class, VS2005/08 version

本文关键字:存在 VS2005 基类 版本 于基类 成员 检查 是否      更新时间:2023-10-16

在检查成员是否存在时,可能在基类C++11版本中,我们从SFINAE开发了一个C++11版的经典成员检查类型特性,以检查继承的成员函数,该函数也适用于C++11final类,但也使用C++11特性(即decltype):

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));
};

自VS2005以来,MSVC一直将final作为名为sealed的非标准扩展,但decltype仅在VS2010中添加。这就留下了VS2005和2008,其中标记为sealed的类仍然打破了经典类型特性,并且不能使用C++11版本。

那么,有没有一种方法可以公式化has_resize_method,使其也适用于VC2005/08 sealed类?

显然,正如使用仅C++11的功能来解决仅C++11问题(final)一样,使用仅VS扩展来解决仅VS2005/08的sealed类问题也是可以的,但如果有一个解决方案适用于所有三组编译器{C++11,{VS2005,VS2008},所有其他},那将是很酷的,但可能要求太多了:)

我提出了一个适用于所有主要编译器的解决方案。遗憾的是,MSVC有一个预处理器检查,因为它抱怨其他编译器的解决方案。主要区别在于MSVC不接受sizeof()内的函数指针,相反,GCC似乎不接受检查中的(&C::resize == 0)。Clang很高兴地接受了这两个。

#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;
}

输出:

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

根据GCC 4.5.3、GCC 4.3.4、Clang 3.0、Visual C++2008和Visual C++2010进行测试。我没有访问Visual C++2005的权限,但我认为它也可以在那里工作。它也在Comeau Online上编译,但我不能保证它在那里产生正确的输出。

同时适用于final类和__sealed类。

请注意,它不仅检查成员函数,而且通常检查成员指针。如果不需要这种行为,您可能需要添加其他检查,如boost::is_member_function_pointer。同样,您可能需要添加对参数/参数类型/结果类型数量的检查——同样,boost在这里非常有用,尤其是boost类型分解。

MSVC自vs2005以来有一个特殊的语句__if_exists。MSDN链接。您可以使用它直接检查成员函数名称。然后检查签名。以下是一个简单的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;