Consider a class which inherits from a std container with a template constructor which calls the underlying constructor of the container. This template constructor works for the simple copy and move constructor but not for the initializer_list ctor.
template<typename container_T>
class test : public container_T {
public:
using container_type = container_T;
test() {}
// templated constructor
template<typename T>
test(T t)
: container_T(t) {}
// without this it won't compile
test(std::initializer_list<typename container_T::value_type> l)
: container_T(l) {}
};
int main() {
test<std::deque<int>> vdi1;
test<std::deque<int>> vdi2({1,2,3,4,5,6,7,8,9});
std::cout << "vdi2 before:" << std::endl;
for(auto it : vdi2)
std::cout << it << std::endl;
test<std::deque<int>> vdi3(std::move(vdi2));
std::cout << "vdi2 before:" << std::endl;
for(auto it : vdi2)
std::cout << it << std::endl;
std::cout << "vdi3 before:" << std::endl;
for(auto it : vdi3)
std::cout << it << std::endl;
return 0;
}
If I remove the initializer_list
constructor vdi2
won't compile. So my question: Why is the initializer_list not deduced by the template constructor? And is it possible to do so?
why is the initializer_list not deduced by the templated constructor?
The reason is that {1,2,3,4,5,6,7,8,9}
is just a synctatic construct that doesn't have a type. Therefore, the compiler cannot deduce a type T
for this synctatic construct and the first constructor fails.
However, by special Standard rules std::initializer_list<T>
(among other things) can be construct from this synctatic construct and T
can be deduced to int
. Hence the second constructor works.
By constrast with function template argument type deduction, with
auto x = {1,2,3,4,5,6,7,8,9};
the compiler sets the type of x to be std::initializer_list<int>
. There are also special Standard rules that says it must be so. Strictly speaking this is not type deduction because, as said above, {1,2,3,4,5,6,7,8,9}
doesn't have a type to be deduced. (The only type deduction happening here is T = int
in std::initializer_list<T>
.) Here the compiler chooses (it doesn't deduce) the type of x
to be std::initializer_list<int>
. In any case, there's no harm to use the abuse of language of saying that the type of x
is deduced to std::initializer_list<int>
.
Finally, as DyP said in the comments, what you probably want is inheriting all constructors (not only those taking one argument) from the base container class. You can do this by removing all the constructors that you currently have and add just this line to test
:
using container_type::container_type;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With