Search code examples
c++templatesvectorc++17template-argument-deduction

What are std::vector deduction guides in C++17?


I read about deduction guides for std::vector from using cppreference.

Example:

#include <vector>

int main() {
   std::vector<int> v = {1, 2, 3, 4};
   std::vector x{v.begin(), v.end()}; // uses explicit deduction guide
}

So, I have some questions about it:

  • What are std::vector deduction guides in C++17?

  • Why and when do we need vector deduction?

  • Here, Is x a std::vector<int> or a std::vector<std::vector<int>>?


Solution

  • What are std::vector deduction guides in C++17?

    An user-defined deduction guide allows users to decide how class template argument deduction deduces arguments for a template class from its constructor arguments. In this case, it seems that std::vector has an explicit guide that should make construction from an iterator pair more intuitive.


    Why and when do we need vector deduction?

    We don't "need" it, but it is useful in generic code and in code that's very obvious (i.e. code where explicitly specifying the template arguments is not beneficial to the reader).


    Is x a vector<int> or a vector<vector<int>>?

    Here's a nice trick to figure this out quickly - write a template function declaration without a definition and attempt to call it. The compiler will print out the type of the passed arguments. Here's what g++ 8 prints out:

    template <typename> 
    void foo();
    
    // ...
    
    foo(x);
    

    error: no matching function for call to foo(std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int> > ...

    As you can see from the error message, x is deduced to std::vector<std::vector<int>::iterator>.


    Why?

    std::vector's deduction guides are available on cppreference.org. The Standard seems to define an explicit deduction guide from an iterator pair:

    enter image description here

    The behavior encountered in g++ 8 seems to be correct regardless, as (quoting Rakete1111)

    • overload resolution prefers the constructor with std::initializer_list with the braced initializer list

    • other constructors are considered only after all std::initializer_list constructors have been tried in list-initialization

    std:vector<std::vector<int>::iterator> is therefore the correct result when using list-initialization. live example

    When constructing x with std::vector x(v.begin(), v.end()), int will be deduced instead. live example