考虑一个从std容器继承的类,该类具有模板构造函数,该构造函数调用容器的基础构造函数。此模板构造函数适用于简单的复制和移动构造函数,但不适用于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;
}
如果删除该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
为be的类型std::initializer_list<int>
。在任何情况下,使用说的类型x
被推导为的语言滥用都是没有害处的std::initializer_list<int>
。
最后,正如DyP在评论中所说,您可能想要的是从基本容器类继承所有构造函数(不仅是带有一个参数的构造函数)。您可以通过删除当前拥有的所有构造函数并将此行添加到以下方式来执行此操作test
:
using container_type::container_type;
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句