类型特征:检查引用成员变量是否为静态
Type trait: Check if reference member variable is static or not
我想检查 class 的成员变量是否是静态的。使用 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
有效(存在成员),它returns std::true_type
.
- 否则它会退回到上次重载和 returns
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
只是在这里"let 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");
如果您想将所有内容封装在 class 中(没有 is_member_
函数,请参阅这两个答案):
我想检查 class 的成员变量是否是静态的。使用 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
有效(存在成员),它returnsstd::true_type
. - 否则它会退回到上次重载和 returns
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
只是在这里"let 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");
如果您想将所有内容封装在 class 中(没有 is_member_
函数,请参阅这两个答案):