为什么 Member Detector fallback 必须是 int?
Why does Member Detector fallback have to be int?
我以为我明白了这个 class(来自这里 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 };
};
但我试图根据我正在寻找成员的情况对其进行调整 double MyTest
。所以我改变了这一行:
struct Fallback { int X; }; // add member name "X"
到
struct Fallback { double MyTest; };
但检测器为所有 class 返回 "true",无论它们是否有 MyTest 成员。我将行更改为:
struct Fallback { int MyTest; };
然后它按预期工作了。
谁能解释为什么回退必须是 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;
}
我的输出是:
1 0
1 1
不一定是int
。它可以是任何类型。您只需在每个地方按类型和名称正确引用它即可:
using Arbitrary = double;
struct Fallback { Arbitrary X; }; // <== arbitrary type, specific name X
和这里:
template<typename U>
static ArrayOfOne & func(Check<Arbitrary Fallback::*, &U::X> *);
// ↑↑↑↑↑↑↑↑↑↑ ↑↑↑
// this type this name
想法是,如果 T
没有 X
,您会找到 Fallback::X
,它将按类型匹配 &U::X
(因为只有一个 - Fallback
中的那个)。但是如果 T
确实有一个 X
,查找将是不明确的。所以 Fallback::X
有什么类型并不重要 - int
只是最短的一个。
请注意,在 C++11 中,使用像 Yakk 的 can_apply
:
这样的东西要容易得多
template <class T>
using x_type = decltype(&T::X);
template <class T>
using has_x = can_apply<x_type, T>;
另请参阅 ,了解比旧式成员检测器更好的其他六种方法。
我以为我明白了这个 class(来自这里 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 };
};
但我试图根据我正在寻找成员的情况对其进行调整 double MyTest
。所以我改变了这一行:
struct Fallback { int X; }; // add member name "X"
到
struct Fallback { double MyTest; };
但检测器为所有 class 返回 "true",无论它们是否有 MyTest 成员。我将行更改为:
struct Fallback { int MyTest; };
然后它按预期工作了。
谁能解释为什么回退必须是 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;
}
我的输出是:
1 0
1 1
不一定是int
。它可以是任何类型。您只需在每个地方按类型和名称正确引用它即可:
using Arbitrary = double;
struct Fallback { Arbitrary X; }; // <== arbitrary type, specific name X
和这里:
template<typename U>
static ArrayOfOne & func(Check<Arbitrary Fallback::*, &U::X> *);
// ↑↑↑↑↑↑↑↑↑↑ ↑↑↑
// this type this name
想法是,如果 T
没有 X
,您会找到 Fallback::X
,它将按类型匹配 &U::X
(因为只有一个 - Fallback
中的那个)。但是如果 T
确实有一个 X
,查找将是不明确的。所以 Fallback::X
有什么类型并不重要 - int
只是最短的一个。
请注意,在 C++11 中,使用像 Yakk 的 can_apply
:
template <class T>
using x_type = decltype(&T::X);
template <class T>
using has_x = can_apply<x_type, T>;
另请参阅