类型特征:检查引用成员变量是否为静态

时间:2016-04-19 06:12:26

标签: c++ c++11 reference typetraits

我想检查一个类的成员变量是否是静态的。使用 std :: is_member_pointer 适用于除引用成员之外的所有类型。

#include <type_traits>

struct A {
  int foo;
};

struct B : A {};

struct C {
  static int foo;
};

struct D : C {
};

struct E {
  int &foo;
};

struct F {
  static int &foo;
};

static_assert(std::is_member_pointer<decltype(&A::foo)>::value, "No");
static_assert(std::is_member_pointer<decltype(&B::foo)>::value, "No");
static_assert(!std::is_member_pointer<decltype(&C::foo)>::value, "No");
static_assert(!std::is_member_pointer<decltype(&D::foo)>::value, "No");

// Fail to compile:
static_assert(std::is_member_pointer<decltype(&E::foo)>::value, "No");

static_assert(!std::is_member_pointer<decltype(&F::foo)>::value, "No");

Live example.

我理解错误,指针不能指向引用成员。但是如何避免它并仍然区分它是静态还是非静态变量?有什么想法吗?

1 个答案:

答案 0 :(得分:2)

如果&E::foo使用SFINAE失败,可以添加回退(如果E::foo根本不存在,则可以添加另一个):

template <typename T>
std::is_member_pointer<decltype(&T::foo)> is_member_foo(int);

template <typename T>
decltype(T::foo, std::true_type{}) is_member_foo(long);

template <typename T>
std::false_type is_member_foo(...);

template <typename T>
using IsMemberFoo = decltype(is_member_foo<T>(0));

static_assert(IsMemberFoo<A>{}, "No");
static_assert(IsMemberFoo<B>{}, "No");
static_assert(!IsMemberFoo<C>{}, "No");
static_assert(!IsMemberFoo<D>{}, "No");
static_assert(IsMemberFoo<E>{}, "No");
static_assert(!IsMemberFoo<F>{}, "No");
static_assert(!IsMemberFoo<G>{}, "No"); // struct G { };

此代码的作用:

  • 如果&T::foo有效,则会使用std::is_member_pointer(您的版本)检查该成员是否为静态。
  • 如果&T::foo无效,则会回退到第二个重载(此处您确定foo不是静态的,或者已经选择了第一个重载):
    • 如果T::foo有效(成员存在),则返回std::true_type
    • 另外,它会回退到最后一次重载并返回std::false_type

另请注意(感谢@iammilind)对于private成员,T::foo 无效,因此将选择第三个重载。

关于ideone的工作示例:http://ideone.com/FILHbK

附注(扩展说明):

  • &T::foo有效时,前两个重载有效,但选择第一个重载,因为int是完全匹配,而long则不是。
  • decltype(T::foo, std::true_type{}):如果T::foo无效,T::foo仅在此处“让SFINAE”回退到第三次重载,但结果类型为std::true_type,这要归功于#define IsMember(MEM) \ template <typename T> \ std::is_member_pointer<decltype(&T::MEM)> is_member_##MEM(int); \ template<typename T> \ decltype(T::MEM, std::true_type{}) is_member_##MEM(long); \ template <typename T> \ std::false_type is_member_##MEM(...); \ template <typename T> \ using IsMember_##MEM = decltype(is_member_##MEM<T>(0)); // Instanciate IsMember_foo IsMember(foo); // Use it: static_assert(IsMember_foo<A>{}, "No"); 逗号运算符。

如果您愿意,还可以创建通用版本(http://ideone.com/lzH2FB):

is_member_

如果要将所有内容封装在一个类中(没有A = (Ax,Ay), B=(Bx,By)函数),也请看这两个答案: