什么是模板推导指南,何时应使用它们?


87

C ++ 17标准引入了“模板推导指南”。我认为它们与在该版本标准中引入的针对构造函数的新模板自变量推论有关,但是我还没有看到关于它们的含义和用途的简单的,常见问题解答风格的解释。

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

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

  • 我该如何申报?



特别是,我很想知道C ++ 17 STL是否确实提供了任何推导指南(例如std :: pair或std :: tuple)。从C ++ 17开始,“可推导”标准模板类型的完整列表是什么?
Quuxplusone


我想知道是否有任何编译器支持此功能。我尝试了gcc,clang和vc ++。rextester.com/DHPHC32332没关系,我发现它仅适用于gc ++ 8.1 C ++ 17和2a g ++ -std = c ++ 17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Jean-Simon布罗楚

Answers:


98

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

最简单的示例是std::vector带有迭代器对的构造函数及其实例。

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

编译器需要弄清楚什么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>;

这告诉编译器,当您调用 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`.

因此,推导仅用于确定正在初始化的类型。一旦确定,初始化的实际过程便会像以前一样工作。


7
嗯,这只是让我想到,即使有了指南,vector v{first, last};也不会做正确的事:(
TC

3
@TC…除非正确的事情是使迭代器成为向量。和std::string{32,'*'}[0] == ' '(对于ASCII)。但是自C ++ 11起,这一切都是正确的。
Arne Vogel

2
分配器矢量参数会发生什么?如果分配器矢量参数没有默认参数,会发生什么?(您无法从InputIterator推论得出)
gnzlbg

@NicolBolas:您是否介意解释在部分或完全专业化类的上下文中隐式和显式推导指南如何工作的细节(其构造函数显然不必具有与主模板的参数类型匹配的参数类型)?通过快速搜索很难找到有关此信息。
user541686 '18

1
@NicolBolas:我明白了。对我来说,这个问题根本不是关于明确的演绎指南的。我认为,如果您只包括您在此评论中的字面意思,那会很有帮助。
user541686 '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.