【问题标题】:What are template deduction guides and when should we use them?什么是模板扣除指南,我们应该在什么时候使用它们?
【发布时间】:2021-10-02 03:38:16
【问题描述】:

C++17 标准引入了“模板推导指南”。我收集它们与此版本标准中引入的构造函数的新模板参数推导有关,但我还没有看到简单的常见问题解答式解释它们是什么以及它们的用途。

  • 什么是 C++17 中的模板推导指南?

  • 我们为什么(以及何时)需要它们?

  • 如何声明它们?

【问题讨论】:

标签: c++ templates c++17 c++-faq template-argument-deduction


【解决方案1】:

模板推导指南是与模板类关联的模式,它告诉编译器如何将一组构造函数参数(及其类型)转换为类的模板参数。

最简单的例子是std::vector 及其采用迭代器对的构造函数。

template<typename Iterator>
void func(Iterator first, Iterator last)
{
  vector v(first, last);
}

编译器需要弄清楚vector&lt;T&gt; 的T 类型是什么。我们知道答案是什么; T 应该是 typename std::iterator_traits&lt;Iterator&gt;::value_type。但是我们如何告诉编译器不必输入vector&lt;typename std::iterator_traits&lt;Iterator&gt;::value_type&gt;?

您使用扣除指南:

template<typename Iterator> vector(Iterator b, Iterator e) -> 
    vector<typename std::iterator_traits<Iterator>::value_type>;

这告诉编译器,当您调用与该模式匹配的vector 构造函数时,它将使用-&gt; 右侧的代码推导出vector 特化。

当从参数中推断类型不是基于这些参数之一的类型时,您需要指南。从initializer_list 初始化vector 显式使用vector 的T,因此不需要指南。

左边不一定指定一个实际的构造函数。它的工作方式是,如果您对一个类型使用模板构造函数推导,它会匹配您针对所有推导指南传递的参数(主模板的实际构造函数提供隐式指南)。如果有匹配,它会使用它来确定要提供给类型的模板参数。

但是一旦推导完成,一旦编译器计算出该类型的模板参数,该类型对象的初始化就会继续进行,就好像没有发生任何事情一样。即选择的推导指南不必与选择的构造函数相匹配。

这也意味着您可以使用带有聚合和聚合初始化的指南:

template<typename T>
struct Thingy
{
  T t;
};

Thingy(const char *) -> Thingy<std::string>;

Thingy thing{"A String"}; //thing.t is a `std::string`.

所以推导指南仅用于确定正在初始化的类型。一旦做出决定,初始化的实际过程就和以前完全一样。

【讨论】:

  • 嗯,我突然想到,即使有向导,vector v{first, last}; 也不会做正确的事:(
  • @T.C. …除非正确的做法是制作一个迭代器向量。和std::string{32,'*'}[0] == ' '(用于ASCII)。但这一切自 C++11 以来都是正确的。
  • 分配器向量参数会发生什么?如果分配器向量参数没有默认参数会发生什么? (不能从 InputIterator 推导出来)
  • @NicolBolas:您介意解释一下隐式和显式推导指南如何在部分或完全专业化类的上下文中工作的细节(其构造函数显然不需要与那些匹配的参数类型的主要模板)?通过快速搜索很难找到这方面的信息。
  • @NicolBolas:我明白了。我不清楚这个问题是否与明确的演绎指南有关……我认为如果您仅在此评论中包含您字面上写的内容,这会很有帮助。
猜你喜欢
  • 2011-09-30
  • 2021-09-07
  • 2010-11-01
  • 1970-01-01
  • 2011-07-04
  • 2017-09-13
  • 2021-12-29
  • 2011-07-17
相关资源
最近更新 更多