I would like to check if a member variable of a class is static or not. Using std::is_member_pointer works fine for all types except for reference members.
#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.
I understand the error, that a pointer cannot point to a reference member. But how to avoid it and still distinguish if it is a static or non static variable? Any idea on that?
Throughout the program, only one copy of the static member variable is created for the entire class hence static member variables are also called class variables. It is shared by all instances of the class. The static member variable is only visible within the class but its lifetime is till the program ends.
A non-static variable can not be accessed by static member functions. A static variable acts as a global variable and is shared among all the objects of the class. A non-static variables are specific to instance object in which they are created.
Here we will see how to initialize the private static member variables initialization in C++. We can put static members (Functions or Variables) in C++ classes. For the static variables, we have to initialize them after defining the class.
A static member function cannot access non-static member variable.
You could add a fallback in case &E::foo
fails using SFINAE (and another one in case E::foo
does not exist at all):
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 { };
What this code does:
&T::foo
is valid, it will check if the member is static or not using std::is_member_pointer
(your version).&T::foo
is not valid, it falls back to the second overload (here you are sure that foo
is not static, or the first overload would have been chosen):
T::foo
is valid (a member exists), it returns std::true_type
.std::false_type
.Also note (thanks to @iammilind) that for private
member, T::foo
is not valid, so the third overload will be chosen.
Working example on ideone: http://ideone.com/FILHbK
Side notes (extended explanation):
&T::foo
is valid, the two first overloads are valid, but the first one is chosen since int
is an exact match while long
is not.decltype(T::foo, std::true_type{})
: T::foo
is only here to "let SFINAE" fall back to the third overload if T::foo
is not valid, but the resulting type is std::true_type
thanks to the comma operator.If you like, you can also create a generic version (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");
Also see these two answers if you want to encapsulate everything in a class (without having is_member_
functions):
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With