Рассмотрим класс, который наследуется от стандартного контейнера с конструктором шаблона, который вызывает базовый конструктор контейнера. Этот конструктор шаблона работает для простого конструктора копирования и перемещения, но не для ctor initializer_list.
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;
}
Если я удалю initializer_list
конструктор vdi2
не скомпилируется. Итак, мой вопрос: почему initializer_list не выводится конструктором шаблона? И возможно ли это сделать?
почему initializer_list не выводится шаблонным конструктором?
Причина в том, что {1,2,3,4,5,6,7,8,9}
это просто синтаксическая конструкция, которая не имеет типа. Следовательно, компилятор не может вывести тип T
для этой синктической конструкции и первый конструктор не удается.
Однако по специальным стандартным правилам std::initializer_list<T>
(среди прочего) может быть построен из этой синктической конструкции и T
можно вывести на int
, Следовательно, второй конструктор работает.
По ограничению с выводом типа аргумента шаблона функции, с
auto x = {1,2,3,4,5,6,7,8,9};
компилятор устанавливает тип x как std::initializer_list<int>
, Есть также специальные Стандартные правила, которые говорят, что так должно быть. Строго говоря, это не вычет типа, потому что, как сказано выше, {1,2,3,4,5,6,7,8,9}
не имеет типа для вывода. (Единственный тип вывода происходит здесь T = int
в std::initializer_list<T>
.) Здесь компилятор выбирает (он не выводит) тип x
быть std::initializer_list<int>
, В любом случае, нет ничего плохого в том, чтобы злоупотреблять языком, говоря, что тип x
выводится std::initializer_list<int>
,
Наконец, как отметил DyP в комментариях, вам, вероятно, нужно наследовать все конструкторы (не только те, которые принимают один аргумент) от базового класса контейнера. Вы можете сделать это, удалив все имеющиеся у вас конструкторы и добавив только эту строку в test
:
using container_type::container_type;
Других решений пока нет …