为什么我尝试使用SFINAE检测静态成员似乎不起作用?

时间:2014-04-19 23:38:32

标签: c++ templates sfinae

我刚刚创建了一个模板来检测类的数据成员是否是静态定义的。在这篇文章中,成员的可访问性不是它应该关注的(假设成员总是可以通过模板访问)。以下是包含任何测试符号的代码:

#include <conio.h>
//#include <stdio.h>
#include <iostream>

struct A1
{
    int a;
};

struct A2
{
    static int a;
};

int A2::a{};

template < class My_Type >
struct TestStatic
{
    template < typename raw_ty > static char fTest(...);

    template < typename class_ty, typename arg_ty = decltype(class_ty::a) >
    static int fTest(int, arg_ty & = class_ty::a);

    enum nRes { result = sizeof(fTest<My_Type>(0)) - 1 };
};

int main(void)
{
    int i;

    i = TestStatic<A1>::result;
    std::cout << i << std::endl;
    i = TestStatic<A2>::result;
    std::cout << i << std::endl;
    _getch();
    return(0);
}

问题是,当它使用g ++ 4.8构建时,编译通过但得到的结果是两个'3'而不是一个'0'和另一个'3'。有什么不对吗?

1 个答案:

答案 0 :(得分:4)

您的方法存在根本缺陷,因为decltype(T::x) is perfectly valid for non-static members

#include <iostream>

struct T
{
    int x;
};

int main()
{
    std::cout << sizeof(decltype(T::x)) << '\n';
}

// Output: 4

您可get what you want使用std::is_member_pointer

  

如果T是指向非静态成员对象的指针或指向非静态成员函数的指针,则提供等于true的成员常量值。对于任何其他类型,值为false

#include <iostream>
#include <type_traits>

struct T
{
    int x;
};

struct S
{
    static int x;
};

int main()
{
    std::cout << !std::is_member_pointer<decltype(&T::x)>::value << ' ';
    std::cout << !std::is_member_pointer<decltype(&S::x)>::value << '\n';
}

// Output: 0 1

这是有效的,因为只有当成员不是::时才通过static语法访问成员才会生成指向成员的指针。当成员为static时,它当然是正常的变量访问。