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

Type trait: Check if reference member variable is static or not

本文关键字:变量 是否是 静态 成员 引用 特征 检查 类型      更新时间:2023-10-16

我想检查一个类的成员变量是否是静态的。使用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");

活生生的例子。

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

如果&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

如果您愿意,还可以创建通用版本(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_函数),请参阅以下两个答案:

  • https://stackoverflow.com/a/36694627/2666289
  • https://stackoverflow.com/a/36693801/2666289