【问题标题】:What does template<typename T, T> mean?模板<typename T, T> 是什么意思?
【发布时间】:2021-10-29 22:21:08
【问题描述】:

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

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

程序输出预测的0 1;

【问题讨论】:

    标签: c++ templates sfinae member-pointers


    【解决方案1】:

    template&lt;typename U, U&gt; 表示有两个模板参数:一个任意类型的 U,以及一个类型为 U 的未命名的非类型模板参数(例如值参数)。例如,int 场景将是 @ 987654323@.

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

    【讨论】:

      【解决方案2】:

      我们先来看看struct Check的声明; template&lt;typename U,U&gt; struct Check 表示模板参数是

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

      Check&lt;int Fallback::*, &amp;U::find&gt;* 有点混乱。

      第一个模板参数是pointer to member.,在这种情况下,它代表一个指向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的初始声明。

      【讨论】:

        【解决方案3】:

        首先,让我们考虑结构Derived。由于它派生自Fallback,它肯定包含一个int 字段find,可能还有一个成员函数find,您要检查其是否存在。

        如上回答所述,struct Check的声明中,第一个模板参数是类型,第二个是非类型参数,类型由第一个参数给出。

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

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

        综上所述:如果template &lt;typename U&gt; func中的U包含成员函数find,则编译器选择func的第二个重载。如果成员函数find 不存在,则编译器选择第一个重载。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-04-05
          • 1970-01-01
          • 1970-01-01
          • 2021-11-16
          • 2011-05-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多