#include <boost/type_index.hpp>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> initv { 42, 31, 7 };
std::vector v1{initv.begin(), initv.end()}; // CTAD
std::vector<int> v2{initv.begin(), initv.end()};
std::cout << boost::typeindex::type_id_with_cvr<decltype(v1)>().pretty_name() << std::endl;
std::cout << boost::typeindex::type_id_with_cvr<decltype(v2)>().pretty_name() << std::endl;
}
output:
std::vector<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, std::allocator<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > > >
std::vector<int, std::allocator<int> >
CTAD produces a vector with iterators, not integers.
Is this correct, given that std::vector
has a constructor that takes iterators ?
This is because of how you initialize the vector. With
std::vector v1{initv.begin(), initv.end()};
You are doing direct-list-initialization which uses the std::initializer_list
constructor and the list contains 2 std::vector<int>::iterator
s. This is why it deduces for iterators.
If you switch to using parentheses instead like
std::vector v1(initv.begin(), initv.end());
then you are no longer using the std::initializer_list
constructor and instead using the iterator range constructor which will correctly deduce the value_type
of the iterators.
To summerize, when you use {}
you are signaling you are using a list of initializers, so that is what is used if it is available.
If you would like to take a deep dive down the rabbit hole that is initialization in C++, I strongly recommend watching Nicolai Josuttis CPPCON talk “The Nightmare of Initialization in C++”