为什么Member Detector后备必须是int?

Dav*_*ria 8 c++ sfinae

我以为我得到了这个课程的想法(从这里https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector):

template<typename T>
class DetectX
{
    struct Fallback { int X; }; // add member name "X"
    struct Derived : T, Fallback { };

    template<typename U, U> struct Check;

    typedef char ArrayOfOne[1];  // typedef for an array of size one.
    typedef char ArrayOfTwo[2];  // typedef for an array of size two.

    template<typename U> 
    static ArrayOfOne & func(Check<int Fallback::*, &U::X> *);

    template<typename U> 
    static ArrayOfTwo & func(...);

  public:
    typedef DetectX type;
    enum { value = sizeof(func<Derived>(0)) == 2 };
};
Run Code Online (Sandbox Code Playgroud)

但是我试着让它适应我正在寻找会员的情况double MyTest.所以我改变了这一行:

struct Fallback { int X; }; // add member name "X"
Run Code Online (Sandbox Code Playgroud)

struct Fallback { double MyTest; };
Run Code Online (Sandbox Code Playgroud)

但无论是否有MyTest成员,探测器都会为所有级别返回"true".我把线改为:

struct Fallback { int MyTest; };
Run Code Online (Sandbox Code Playgroud)

然后它按预期工作.

任何人都可以解释为什么后备必须是一个int而不是你实际上正在寻找的成员的类型?

这是一个例子,我将X视为int,而Y视为double:

#include <iostream>
#include <vector>

// https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector

// Standard point representation
struct Point3
{
    double X,Y,Z;
};

struct SomethingElse{};

template<typename T>
class DetectX
{
    struct Fallback { int X; }; // add member named "X"
    struct Derived : T, Fallback { };

    template<typename U, U> struct Check;

    typedef char ArrayOfOne[1];  // typedef for an array of size one.
    typedef char ArrayOfTwo[2];  // typedef for an array of size two.

    template<typename U>
    static ArrayOfOne & func(Check<int Fallback::*, &U::X> *);

    template<typename U>
    static ArrayOfTwo & func(...);

  public:
    typedef DetectX type;
    enum { value = sizeof(func<Derived>(0)) == 2 };
};

template<typename T>
class DetectY
{
    struct Fallback { double Y; }; // add member named "Y"
    struct Derived : T, Fallback { };

    template<typename U, U> struct Check;

    typedef char ArrayOfOne[1];  // typedef for an array of size one.
    typedef char ArrayOfTwo[2];  // typedef for an array of size two.

    template<typename U>
    static ArrayOfOne & func(Check<double Fallback::*, &U::X> *);

    template<typename U>
    static ArrayOfTwo & func(...);

  public:
    typedef DetectY type;
    enum { value = sizeof(func<Derived>(0)) == 2 };
};

int main()
{
  std::cout << DetectX<Point3>::value << " " << DetectX<SomethingElse>::value << std::endl;

  std::cout << DetectY<Point3>::value << " " << DetectY<SomethingElse>::value << std::endl;

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的输出是:

1 0

1 1

Bar*_*rry 4

不一定是这样int. It can be of any type. You just have to refer to it correctly, by type and name, in every place:

\n\n
using Arbitrary = double;\n\nstruct Fallback { Arbitrary X; }; // <== arbitrary type, specific name X\n
Run Code Online (Sandbox Code Playgroud)\n\n

here:

\n\n
template<typename U> \nstatic ArrayOfOne & func(Check<Arbitrary Fallback::*, &U::X> *);\n//                             \xe2\x86\x91\xe2\x86\x91\xe2\x86\x91\xe2\x86\x91\xe2\x86\x91\xe2\x86\x91\xe2\x86\x91\xe2\x86\x91\xe2\x86\x91\xe2\x86\x91                \xe2\x86\x91\xe2\x86\x91\xe2\x86\x91\n//                             this type              this name\n
Run Code Online (Sandbox Code Playgroud)\n\n

这个想法是,如果T没有X,您会找到Fallback::X,它将&U::X按类型匹配(因为只有一个 - 中的那个Fallback)。但如果T确实有X,则查找将不明确。所以什么类型并不重要Fallback::X-int只是最短的类型。

\n\n

请注意,在 C++11 中,使用 Yakk\'s 之类的东西会更容易can_apply

\n\n
template <class T>\nusing x_type = decltype(&T::X);\n\ntemplate <class T>\nusing has_x = can_apply<x_type, T>;\n
Run Code Online (Sandbox Code Playgroud)\n\n

另请参阅此问题,了解其他六种比旧式成员检测器更好的方法。

\n