7

我正在阅读这个史前元程序示例来检测一个类是否支持成员查找。(或任何其他成员)。

template<typename T>
class DetectFind
{
    struct Fallback { int find; }; 
    struct Derived : T, Fallback { };

    template<typename U, U> struct Check;

    typedef char Yes[1];  
    typedef char No[2]; 

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

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

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

int main()
{
    std::cout << DetectFind<std::vector<int> >::value << std::endl;
    std::cout<< DetectFind<std::set<int> >::value << std::endl;
}

直觉上我确实理解这背后的目的,但如果有人让我在 10 天后从头开始写同样的东西,我可能会失败。
原因是我不完全理解这里使用的句法和语言延伸。
有人可以解释以下语法的含义吗?

  1. Check<int Fallback::*, &U::find>* (我知道它在这里试图从 SFIAN 中受益,但是这是如何检测到 find 的存在,我相信这也与第二个问题有关)
  2. template<typename U, U> struct Check;

程序按预期输出 0 1 ;

4

3 回答 3

6

template<typename U, U>表示有两个模板参数:一个任意类型 U,以及一个类型为 U 的未命名的非类型模板参数(例如值参数)。例如,int场景是ClassName<int,42>.

在您的示例中,类型U是指向int成员的指针,值是int成员的地址。

于 2021-08-31T10:02:27.517 回答
1

让我们首先介绍 ; 的声明struct Checktemplate<typename U,U> struct Check表示模板参数是

  1. 普通类型U
  2. 类型的对象,U没有名称。

Check<int Fallback::*, &U::find>*有点混乱。

第一个模板参数是一个指向成员的指针。,在这种情况下,它代表指向class Fallback类型成员的指针int,这将允许我们编写类似这样的内容。

Fallback obj{10};
int Fallback::* find_ptr = &Fallback::find;
std::cout << obj.*find << std::endl;   //prints 10, note: ".*" is a separate operator

模板的第二个参数是成员的地址class U,作为struct Check建议的初始声明。

于 2021-08-31T10:14:38.710 回答
1

首先,让我们考虑一下 struct Derived。因为它派生自Fallback它肯定包含一个 int 字段find,可能还有一个成员函数find,它的存在是您想要检查的。

如上面的答案所述,在 的声明中struct Check,第一个模板参数是类型,第二个是非类型参数,属于第一个参数给定的类型。

鉴于此,让我们检查 的两个重载func。第一个重载接受一个指向结构的指针,其第一个模板参数的类型等于( )Check的指向 int 成员的指针。然后,第二个模板参数被解释为一个指向 int 的成员,其值为。给定,如果包含成员函数,则第二个参数 of是不明确的,因为它也可以引用由继承的。通过 SFINAE,这个重载将被丢弃。Fallbackint Fallback::*&U::findU = DerivedTfindCheckint findFallbackfunc

第二个func重载总是定义明确的。但是如果第一个重载没有被丢弃,那么第二个重载就不那么专业了,所以编译器会选择第一个重载。

综上所述:如果Uintemplate <typename U> func包含成员函数find,编译器会选择 的第二个重载func。如果成员函数find不存在,编译器会选择第一个重载。

最后, 的值DetectFind由 selected 的返回类型的大小决定func,取决于重载是大小为 1 或 2 的 char 数组。从那里,您可以得到func选择的重载,从上面的讨论中,是否T有成员函数find

于 2021-08-31T10:36:57.417 回答