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

Viatorus

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?

Holt

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):

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Type trait for member template static function

From Dev

Type trait for member template static function

From Dev

enum and static const member variable usage in template trait class

From Dev

"Undefined reference" to declared C++ static member variable

From Dev

const reference to static member

From Dev

Non Static Member Reference

From Java

Pointer to member variable as static member

From Dev

Returning a trait type with static dispatch

From Dev

Reference to self type in parameterized trait

From Dev

Reference associated type in trait bounds

From Dev

How to constrain type as abstract type member in trait?

From Dev

Static member instance reference issue

From Dev

Reference to static member function & inheritance

From Dev

Reference methods from static member

From Dev

static variable - undefined reference

From Dev

Behaviour of the static reference variable

From Dev

trait to drop const from a member function type?

From Dev

Unity Static member `UpgradeManager.tickValue' cannot be accessed with an instance reference, qualify it with a type name instead

From Dev

static member variable in class template

From Dev

Initialize static atomic member variable

From Dev

constexpr static member vs variable

From Dev

static const member variable initialization

From Dev

Static member variable such as OOP langage

From Dev

Initialize static atomic member variable

From Dev

Instantiation of template static member variable

From Dev

static member variable initializing twice

From Dev

Iterator with Static Array Member variable

From Dev

Initializing reference member variable with literal

From Dev

Assigning rvalue reference to member variable

Related Related

HotTag

Archive