什么是模板扣除指南? 我们应该在什么时候使用它们?

C + + 17标准引入了“模板演绎指南”。我知道这些都是与这个版本的标准中引入的构造函数的新模板参数演绎有关,但是我还没有看到一个简单的,常见问题风格的关于它们是什么以及它们是用来做什么的解释。

  • 什么是 C + + 17中的模板演绎指南?

  • 为什么(什么时候)我们需要他们?

  • 我怎么申报?

18053 次浏览

Template deduction guides are patterns associated with a template class that tell the compiler how to translate a set of constructor arguments (and their types) into template parameters for the class.

The simplest example is that of std::vector and its constructor that takes an iterator pair.

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

The compiler needs to figure out what vector<T>'s T type will be. We know what the answer is; T should be typename std::iterator_traits<Iterator>::value_type. But how do we tell the compiler without having to type vector<typename std::iterator_traits<Iterator>::value_type>?

You use a deduction guide:

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

This tells the compiler that, when you call a vector constructor matching that pattern, it will deduce the vector specialization using the code on the right of ->.

You need guides when the deduction of the type from the arguments is not based on the type of one of those arguments. Initializing a vector from an initializer_list explicitly uses the vector's T, so it doesn't need a guide.

The left side doesn't necessarily specify an actual constructor. The way it works is that, if you use template constructor deduction on a type, it matches the arguments you pass against all deduction guides (actual constructors of the primary template provide implicit guides). If there is a match, it uses that to determine which template arguments to provide to the type.

But once that deduction is done, once the compiler figures out the template parameters for the type, initialization for the object of that type proceeds as if none of that happened. That is, the deduction guide selected does not have to match the constructor selected.

This also means that you can use guides with aggregates and aggregate initialization:

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


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


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

So deduction guides are only used to figure out the type being initialized. The actual process of initialization works exactly as it did before, once that determination has been made.