在C++11之前的代码中,如果我正在寻找一个我不知道类型的成员变量,我如何使用SFINAE来检查该成员是否存在?
下面是一个使用您要求的成员检测器习惯用法的示例:
template<typename T>
struct has_x {
typedef char(&yes)[1];
typedef char(&no)[2];
// this creates an ambiguous &Derived::x if T has got member x
struct Fallback { char x; };
struct Derived : T, Fallback { };
template<typename U, U>
struct Check;
template<typename U>
static no test(Check<char Fallback::*, &U::x>*);
template<typename U>
static yes test(...);
static const bool value = sizeof(test<Derived>(0)) == sizeof(yes);
};
#include <iostream>
struct A { private: int x; }; // works with private, too
struct B { const char x; };
struct C { void x() volatile ; };
struct D : A { };
struct E {};
struct F : A, B {}; // note that &F::x is ambiguous, but
// the test with has_x will still succeed
int main()
{
std::cout
<< has_x<A>::value // 1
<< has_x<const B>::value // 1
<< has_x<volatile C>::value // 1
<< has_x<const volatile D>::value // 1
<< has_x<E>::value // 0
<< has_x<F>::value; // 1
}
现场测试。
它也应该与MSVC一起工作。
以下是我在GCC和Clang的新版本以及Visual C++的新版本和旧版本上检查的解决方案:
#if defined(_MSC_VER) && _MSC_VER < 1400
#define GEN_MEMBER_CHECKER(Prefix, Member)
template<class T> struct Prefix##Member
{ enum { __if_not_exists(T::Member) { value = 0 } __if_exists(T::Member) { value = 1 } }; };
#else
#define GEN_MEMBER_CHECKER(Prefix, Member)
template<class T> struct Prefix##Member;
template<class T> struct Prefix##Member<T const> : Prefix##Member<T> { };
template<class T> struct Prefix##Member<T volatile> : Prefix##Member<T> { };
template<class T> struct Prefix##Member<T volatile const> : Prefix##Member<T> { };
template<class T> struct Prefix##Member<T &> : Prefix##Member<T> { };
template<class T> struct Prefix##Member<T *> { enum { value = 0 }; };
template<> struct Prefix##Member<void>
{
private:
template<class T> static unsigned char (&test(int, T const &))[1U + 1U];
static unsigned char (&test(int, ...))[1U];
public:
template<class T>
static unsigned char (&check(int, Prefix##Member<T> *))[1U + sizeof(test(0, &T::Member))];
static unsigned char (&check(int, ...))[1U];
};
template<class T> struct Prefix##Member
{ enum { value = sizeof(Prefix##Member<void>::check(0, (Prefix##Member *)0)) > 2U }; }
#endif
示例:
#include <stdio.h>
GEN_MEMBER_CHECKER(member_check_, Member);
struct HasMember { int Member; };
struct DoesntHaveMember { };
int main()
{
printf("%u %un",
member_check_Member<HasMember>::value,
member_check_Member<DoesntHaveMember>::value);
}
输出:
1 0