什么是模板扣除指南以及何时使用它们?

Tri*_*dle 78 c++ templates c++-faq template-argument-deduction c++17

C++ 17标准引入了"模板推导指南".我认为它们与此版本标准中引入的构造函数的新模板参数推导有关,但我还没有看到一个简单的,常见问题解答风格的解释,它们是什么以及它们的用途.

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

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

  • 我该如何申报?

Nic*_*las 90

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

最简单的例子是std::vector和它的构造函数,它采用迭代器对.

template<typename Iterator>
void func(Iterator first, Iterator last)
{
  vector v(first, last);
}
Run Code Online (Sandbox Code Playgroud)

编译器需要弄清楚它vector<T>T类型.我们知道答案是什么; T应该是typename std::iterator_traits<Iterator>::value_type.但是我们怎么告诉编译器不必输入vector<typename std::iterator_traits<Iterator>::value_type>

您使用演绎指南:

template<typename Iterator> vector(Iterator b, Iterator e) -> 
    vector<typename std::iterator_traits<Iterator>::value_type>;
Run Code Online (Sandbox Code Playgroud)

这告诉编译器,当你调用vector匹配该模式的构造函数时,它将vector使用右边的代码推导出特化->.

当从参数中推断出类型不是基于其中一个参数的类型时,您需要指南.初始化vectorinitializer_list明确使用vectorT,所以它并不需要一个向导.

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

但是一旦完成了这种推论,一旦编译器计算出该类型的模板参数,那么该类型对象的初始化就好像没有发生这种情况一样.也就是说,所选的演绎指南不必与所选的构造函数匹配.

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

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

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

Thingy thing{"A String"}; //thing.t is a `std::string`.
Run Code Online (Sandbox Code Playgroud)

因此,演绎指南仅用于确定正在初始化的类型.一旦做出确定,实际的初始化过程就像以前一样.

  • @TC:这是你的"统一初始化". (10认同)
  • 嗯,它刚刚发生在我身上,即使有了指南,`vector v {first,last};`也不会做正确的事:( (5认同)
  • @TC…除非正确的事情是使迭代器成为向量。和``std :: string {32,'*'} [0] ==''``(对于ASCII)。但是,自C ++ 11起,这一切都是正确的。 (3认同)
  • 分配器向量参数会发生什么?如果分配器向量参数没有默认参数会发生什么?(你不能从 InputIterator 推导出来) (2认同)