c++ - 类型特征 : Check if reference member variable is static or not

标签 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.

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

最佳答案

如果 &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 只是为了“让 SFINAE”退回到第三重载如果 T::foo 无效,但由于逗号运算符,结果类型为 std::true_type

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

#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");

如果您想将所有内容封装在一个类中(没有 is_member_ 函数),另请参阅这两个答案:

关于c++ - 类型特征 : Check if reference member variable is static or not,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36709958/

相关文章:

java - 字符串 toString() 方法

delphi - 一个简单的delphi表单应用程序是否需要任何库或依赖项来部署?

c++ - 传递指针 - 用于写入流

c++ - 为什么 "auto ch = unsigned char{' p'}"在 C++ 17 下不能编译?

c++ - 使用 Yocto 编译和加载内核模块驱动程序

c++ - "long double"有一个单词名称吗?

c++ - 有没有优化 x86 二进制代码的库?

c++ - 是否可以在构造函数之前调用 C++ 对象实例的析构函数?如果是这样,如何?

C++:ostream << 运算符错误

c++ - 从字符串 vector 初始化二维数组的最简单方法是什么?