3

检查成员是否存在,可能在基类中,C++11 版本中,我们开发了 SFINAE 的经典成员检查类型特征的 C++11 版本,以检查也适用于 C++的继承的成员函数11 个final类,但也使用 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));
};

MSVC自 VS2005 起final作为非标准扩展名,但仅在 VS2010 中添加。剩下的 VS2005 和 2008 中,标记为的类仍然破坏了经典的类型特征,并且不能使用 C++11 版本。sealeddecltypesealed

那么,有没有办法制定has_resize_method它也适用于 VC2005/08sealed类?

显然,正如使用仅限 C++11 的功能来解决仅限 C++11 的final问题sealed(如果有一个适用于所有三组编译器 {C++11,{VS2005,VS2008},all others} 的解决方案,那会很酷,但可能要求太多了:)

4

2 回答 2

4

我能够想出一个适用于所有主要编译器的解决方案。可悲的是,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 在这里会非常有帮助,尤其是。升压型分解

于 2012-03-11T13:28:24.983 回答
2

MSVC 自 vs2005 以来有一个特殊的声明__if_existsMSDN 链接在这里。您可以使用它直接检查成员函数名称。然后检查签名。以下是一个简单的 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;
于 2012-03-10T04:17:39.853 回答