正在检查成员是否存在,可能存在于基类VS2005/08版本中
Checking a member exists, possibly in a base class, VS2005/08 version
在检查成员是否存在时,可能在基类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;
- C++模板来检查友元函数的存在
- 既然存在危险,为什么项目要使用-I include开关
- 我们可以访问一个不存在的联盟的成员吗
- C++:对不存在的命名空间使用命名空间指令
- C++quit()函数中可能存在作用域问题
- C++擦除(如果存在)
- g++ 说函数不存在,即使包含正确的标头
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 有了gcc,是否可以链接库,但前提是它存在
- C++LinkedList问题.数据类型之间存在冲突?没有匹配的构造函数
- gcc和clang在表达式是否为常量求值的问题上存在分歧
- C++Builder中的OnClick事件签名存在问题
- 如何正确地将分支添加到已存在的树中
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- 如何检查QList中是否存在值
- 根据某个函数是否存在启用模板
- 如何将分支添加到已存在的TTree:ROOT
- 地图计数确实很重要,或者只是检查是否存在
- VS2005调试模式和发布模式之间存在巨大的性能影响
- 正在检查成员是否存在,可能存在于基类VS2005/08版本中