什么是模板演绎指南,我们应该在什么时候使用它们?

What are template deduction guides and when should we use them?

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

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

最简单的示例是 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 特化。

当从参数中推导类型不是基于其中一个参数的类型时,您需要指南。从 initializer_list 初始化 vector 显式使用 vectorT,因此它不需要指南。

左侧不一定指定实际的构造函数。它的工作方式是,如果您在类型上使用模板构造函数推导,它会将您传递的参数与所有推导指南相匹配(主模板的实际构造函数提供隐式指南)。如果存在匹配项,它会使用该匹配项来确定向该类型提供哪些模板参数。

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

这也意味着您可以将指南与聚合和聚合初始化一起使用:

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

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

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

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