Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 962
Viatorus Avatar asked Apr 19 '16 06:04

Viatorus


People also ask

Can a member variable be static?

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.

Is static variable same as static member?

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.

Can static members be private C++?

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.

Can a static member function access member variable of an object?

A static member function cannot access non-static member variable.


1 Answers

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:

  • If &T::foo is valid, it will check if the member is static or not using std::is_member_pointer (your version).
  • If &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):
    • If T::foo is valid (a member exists), it returns std::true_type.
    • Otherwize it falls back to the last overload and returns 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):

  • When &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):

  • https://stackoverflow.com/a/36694627/2666289
  • https://stackoverflow.com/a/36693801/2666289
like image 101
Holt Avatar answered Oct 11 '22 01:10

Holt