It’s not the concept as a whole, but rather one of the methods it uses to determine if a class has an n data-member. Here is the full code; an ordinary use of SFINAE for member detection.
template <typename T>
struct has_X {
struct Fallback { int X; };
struct Derived : T, Fallback {};
template <typename U, U> struct S;
template <typename C> static char (&f(S<int Fallback::*, &C::X> *))[1];
template <typename C> static char (&f(...))[2];
public:
const static bool value = sizeof(f<Derived>(0)) == 2;
};
The part where Derived inherits from both Fallback and T confuses me because when we do the overload of f, &C::X is &Derived::X. But shouldn’t this overload always be chosen because isn’t Derived guaranteed to have X since it inherits from Fallback which has that data-member?
Maybe I’m overlooking something. However, this single piece of code has shown and taught me things I never knew, so maybe there is something to this. What I would expect is for that overload to always be chosen (not the one with the ...) because Derived should always have X since it inherits from Fallback. But this is not the case. Can someone please explain why?
Fallbackhas one data member namedX, but Derived will have two ifTalso has a member namedX, in which caseDerived::Xcannot be taken unambiguously. So ifTdoes not haveX, the first overload is used, and ifThasX, the second more general version is used. This is why you can tell these cases apart depending on the size of their return types.