Search code examples
c++c++17ctad

Why does std::vector CTAD accept both int and double?


#include <boost/type_index.hpp>
#include <iostream>
#include <vector>

int main()
{
    std::vector v{2, 3.14};
    std::cout << boost::typeindex::type_id_with_cvr<decltype(v)>().pretty_name() << '\n';

    std::cout << "size: " << v.size() << '\n';
    for (auto x : v)
        std::cout << "- " << x << '\n';
}

The output is:

std::vector<double, std::allocator<double> >
size: 2
- 2
- 3.14

std::vector instantiation uses auto-type-deduction (CTAD).

Apparently, the initializer_list constructor is used (checked), but why does it accept both an int and a double and still deduces the type as vector<double> ?
If I increase the number of elements (while mixing int and double), compilation fails.

The same result with gcc and clang

$ g++ --version
g++ (GCC) 13.0.1 20230401 (Red Hat 13.0.1-0)

$ clang++ --version
clang version 16.0.1 (Fedora 16.0.1-1.fc38)

Solution

  • There are two instances of overload resolution happening here. The first is to deduce the template argument. Since the two types in the init-list are different, the size+value constructor (or more formally, the deduction guide generated from said constructor) is picked here, deducing the type to be double.

    Then overload resolution runs again to create the object. With the type now known as double, the list constructor is now valid, and thus used to initialize the object.