124

The C++17 standard introduces "template deduction guides". I gather they're something to do with the new template argument deduction for constructors introduced in this version of the standard, but I haven't yet seen a simple, FAQ-style explanation of what they are and what they're for.

  • What are template deduction guides in C++17?

  • Why (and when) do we need them?

  • How do I declare them?

Tristan Brindle
  • 16,281
  • 4
  • 39
  • 82
  • 4
    http://en.cppreference.com/w/cpp/language/class_template_deduction – doug Dec 03 '16 at 19:37
  • In particular, I'd be interested to know whether any deduction guides are actually provided by the C++17 STL (e.g. for std::pair or std::tuple). What's the complete list of "deducible" standard template types as of C++17? – Quuxplusone Feb 21 '17 at 01:42
  • 1
    @Quuxplusone http://en.cppreference.com/w/cpp/utility/pair/deduction_guides and http://en.cppreference.com/w/cpp/utility/tuple/deduction_guides – Cubbi Mar 08 '18 at 00:26
  • I'd be interested to know if any compiler supports this. I tried gcc, clang and vc++. https://rextester.com/DHPHC32332 Nevermind, I found it works only with gc++ 8.1 C++17 and 2a g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out – Jean-Simon Brochu Feb 04 '19 at 14:24

1 Answers1

130

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 8
    Hmm, it just occurred to me that even with the guide, `vector v{first, last};` won't do the right thing :( – T.C. Dec 03 '16 at 20:02
  • 3
    @T.C. … unless the right thing is making a vector of iterators. And ``std::string{32,'*'}[0] == ' '`` (for ASCII). But this has all been true since C++11. – Arne Vogel Oct 20 '17 at 14:16
  • 2
    what happens with the allocator vector parameter ? what would happend if the allocator vector parameter wouldn't have a default argument? (you cannot deduce it from InputIterator) – gnzlbg Oct 27 '17 at 16:19
  • @NicolBolas: Would you mind explaining the details of how implicit and explicit deduction guides can work in the context of partially or fully specialized classes (whose constructors clearly need don't have to have parameter types matching those of the primary template)? It's hard to find information on this through a quick search. – user541686 Jul 13 '18 at 13:25
  • @Mehrdad: The only caveat where specialization matters is that implicit guides are only generated from the *primary* template's constructors, not from specializations. Beyond that, specialization is irrelevant to the rules of class deduction. But since this question is about *explicit* deduction guides, that's kind of off-topic. – Nicol Bolas Jul 13 '18 at 13:29
  • 1
    @NicolBolas: I see. It's not clear to me that the question is about explicit deduction guides at all... I think it's helpful if you just include what you literally wrote in this comment. – user541686 Jul 13 '18 at 13:35