template<typename T>struct X{ template<typename... Args> X(Args&&... args) : t(std::forward<Args>(args)...) // ? /* or */ : t{std::forward<Args>(args)...} // ?private: T t;};
如果我想存储的对象是std :: vector并且我选择了花括号样式(uniform-initialization),那么我传递的参数将被转发到vector :: vector(std :: initializer_List< T>)构造函数,这可能是也可能不是我想要的.
另一方面,如果我使用非大括号样式,我将失去通过其std :: initializer_List构造函数向向量添加元素的能力.
当我不知道我存储的对象和将传入的参数时,我应该使用什么形式的初始化?
解决方法 为了清楚起见,对于具有多个构造函数的类型产生了歧义,包括一个使用std :: initializer_List,另一个构造函数的参数(当用大括号初始化时)可能被编译器解释为std :: initializer_List.例如,使用std :: vector< int>就是这种情况. :template<typename T>struct X1{ template<typename... Args> X1(Args&&... args) : t(std::forward<Args>(args)...) {} T t;};template<typename T>struct X2{ template<typename... Args> X2(Args&&... args) : t{std::forward<Args>(args)...} {} T t;};int main() { auto x1 = X1<std::vector<int>> { 42,2 }; auto x2 = X2<std::vector<int>> { 42,2 }; std::cout << "size of X1.t : " << x1.t.size() << "\nsize of X2.t : " << x2.t.size();}
(注意,唯一的区别是X2成员初始化列表中的大括号而不是X1成员初始化列表中的括号)
Output :
size of X1.t : 42
size of X2.t : 2
Demo
标准库作者在编写实用程序模板时遇到了这个问题,例如std :: make_unique,std :: make_shared或std :: optional<> (应该完全转发任何类型):首选哪种初始化形式?这取决于客户端代码.
没有好的答案,他们通常使用括号(理想情况下记录选择,因此调用者知道会发生什么).习惯性的现代c 11更喜欢在任何地方进行支撑初始化(它避免缩小转换,避免c最令人烦恼的解析等).
消除歧义的潜在解决方法是使用命名标记,在Andrzej’s C++ blog这篇伟大的文章中广泛讨论:
namespace std{ constexpr struct with_size_t{} with_size{}; constexpr struct with_value_t{} with_value{}; constexpr struct with_capacity_t{} with_capacity{};}// These contructors do not exist.std::vector<int> v1(std::with_size,10,std::with_value,6);std::vector<int> v2{std::with_size,6};
这是详细的,并且只有在您可以修改歧义类型时才适用(例如,暴露构造函数的类型采用std :: initializer_List和其参数列表可能转换为std :: initializer列表的其他构造函数)
总结以上是内存溢出为你收集整理的c – 初始化时的统一或直接初始化?全部内容,希望文章能够帮你解决c – 初始化时的统一或直接初始化?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)