C++ 关于成员检测代码的说明

C++ 关于成员检测代码的说明,c++,C++,它不是作为一个整体的概念,而是它用来确定类是否有n数据成员的方法之一。这是完整的代码;SFINAE用于成员检测的一般用途 template <typename T> struct has_X { struct Fallback { int X; }; struct Derived : T, Fallback {}; template <typename U, U> struct S; template <typename C>

它不是作为一个整体的概念,而是它用来确定类是否有
n
数据成员的方法之一。这是完整的代码;SFINAE用于成员检测的一般用途

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;
};
模板
结构具有{
结构回退{int X;};
派生结构:T,回退{};
模板结构;
模板静态字符&f(S*)[1];
模板静态字符(&f(…)[2];
公众:
常量静态布尔值=sizeof(f(0))==2;
};
Derived
继承自
Fallback
T
的部分让我感到困惑,因为当我们执行
f
的重载时,
&C::X
&Derived::X
。但是这个重载不应该总是被选择,因为
派生的
不是保证有
X
,因为它继承了具有该数据成员的
回退


也许我忽略了什么。然而,这段代码向我展示并教会了我一些我不知道的东西,所以也许这其中有一些东西。我希望总是选择该重载(而不是带有
..
的重载),因为
派生的
应该始终具有
X
,因为它继承自
回退
。但事实并非如此。有人能解释一下原因吗?

Fallback
有一个名为
X
的数据成员,但是如果
T
也有一个名为
X
的成员,则派生将有两个,在这种情况下,不能明确地采用
派生::X
。因此,如果
T
没有
X
,则使用第一个重载,如果
T
X
,则使用第二个更通用的版本。这就是为什么你可以根据返回类型的大小来区分这些情况。

你是说
S
?@NateKohl是的,很抱歉我是从内存中写的……顺便说一句,看起来你颠倒了逻辑(
value
true
如果
T
没有
X
)。与1比较或切换
f
的返回类型。@AndersJohansson感谢您指出这一点。我的错误你的意思不是含糊不清吗?@David,不是-如果
t
有一个名为
X
的成员,那么
派生的::X
就不能被明确地接受,即
派生的::X
是含糊不清的。对于双重否定表示抱歉;)好的,顺便说一句,回答得很好。:)