This question is based on this post.
Goal: I would like to know if a class has the member variable x. I would like to receive true
The following seems to work. Please tell me if it needs improvement. Live example.
class Haser {
public:
template <typename T, typename = int>
static constexpr bool HasX = false;
template <typename T>
static constexpr bool HasX<T, decltype((void) T::x, 0)> = true;
};
struct A {
private:
int x;
friend Haser;
};
Haser::HasX<A> is true.
Well... not sure about correctness and limits of this solution... but...
If you define an helper struct with an x element accessible
struct check_x_helper
{ int x; };
you can write a template struct that inherit from both check_x_helper and the class you want to see if contain a x member
template <typename T>
struct check_x : public T, check_x_helper
Inside check_x you can declare (declare only: are used inside a decltype()) as follows
template <typename U = check_x, typename = decltype(U::x)>
static constexpr std::false_type check (int);
static constexpr std::true_type check (long);
Observe the first one, the template one: when the checked class (T) contains an x member, the decltype(U::x) is ambiguous because x is inherited from both T and check_x_helper, so this function is SFINAE discarded.
On contrary, when T doesn't contains an x member, there isn't an ambiguity, the decltype(U::x) is the type of check_x_helper::x (int) and the first check() function remain enabled.
Now you need something as
using type = decltype(check(0));
static constexpr auto value = type::value;
to call check(0) (the int parameter express the preference to the template version) and save the detected value in a static constexpr variable.
The following is a full compiling example
#include <iostream>
#include <utility>
class foo
{ int x; };
struct bar
{ };
struct check_x_helper
{ int x; };
template <typename T>
struct check_x : public T, check_x_helper
{
template <typename U = check_x, typename = decltype(U::x)>
static constexpr std::false_type check (int);
static constexpr std::true_type check (long);
using type = decltype(check(0));
static constexpr auto value = type::value;
};
int main()
{
std::cout << check_x<foo>::value << std::endl;
std::cout << check_x<bar>::value << std::endl;
}
Drawback of this solution: decltype(U::x) fail (ambiguity) also when T declare x as a method or as a using type. So given
class foo
{ int x () { return 0;} ; };
or
class foo
{ using x = int; };
from check_x<foo>::value you obtain 1.