Pot*_*ter 11 c++ initializer-list c++11
编辑:在我们开始之前,这个问题不是关于正确使用std::initializer_list
; 它是关于在需要方便的语法时应该传递什么.谢谢你坚持主题.
C++ 11引入std::initializer_list
了定义接受braced-init-list参数的函数.
struct bar {
bar( char const * );
bar( int );
} dog( 42 );
fn foo( std::initializer_list< bar > args );
foo( { "blah", 3, dog } );
Run Code Online (Sandbox Code Playgroud)
语法很好,但由于各种问题,它很糟糕:
他们无法有意义地感动.上述功能必须dog
从列表中复制; 这不能转换为移动建筑或省略.仅移动类型根本无法使用.(好吧,const_cast
实际上是一个有效的解决方法.如果有一篇关于这样做的文章,我希望看到它.)
也没有constexpr
语义.(这在C++ 1y即将发布.但这是一个小问题.)
const
不像其他地方那样传播; 的initializer_list
是从来没有const
,但它的内容始终是.(因为它不拥有其内容,所以它不能对副本进行写访问,尽管将它复制到任何地方都很少是安全的.)
该initializer_list
对象不拥有其存储(yikes); 它与提供存储的完全独立的裸阵列(yikes)的关系被隐含地定义(yikes)作为引用与绑定临时(四倍yikes)的关系.
我相信这些事情会在适当的时候得到解决,但是现在是否有最佳实践来获得没有硬编码的优势initializer_list
?是否有关于直接依赖它的文献或分析?
显而易见的解决方案是通过值传递标准容器,例如std::vector
.一旦将对象从中复制到其中initializer_list
,它就会被移动构造为按值传递,然后您可以移出内容.改进是在堆栈上提供存储.一个好的图书馆也许能提供大部分的优点initializer_list
,array
和vector
,甚至不需要使用前者.
有资源吗?
它是关于在需要方便的语法时应该传递什么.
如果你想要大小的方便(即:用户只是键入一个{}
没有函数调用或单词的列表),那么你必须接受一个正确的所有权力和限制initializer_list
.即使你试图将它转换成其他东西,比如某种形式array_ref
,你仍然需要initializer_list
在它们之间有一个中介.这意味着您无法解决您遇到的任何问题,例如无法摆脱它们.
如果它通过了initializer_list
,那么你必须接受这些限制.因此,替代方案是不经历一个initializer_list
,这意味着你将不得不接受某种形式的具有特定语义的容器.替代类型必须是聚合,因此替代对象的构造不会遇到相同的问题.
因此,您可能正在考虑强制用户创建std::array
(或语言数组)并传递它.您的函数可以采用某种形式的array_ref
类,可以从任意大小的任何数组构造,因此消耗函数不限于一个大小.
但是,你失去了大小的便利:
foo( { "blah", 3, dog } );
Run Code Online (Sandbox Code Playgroud)
与
foo( std::array<bar, 3>{ "blah", 3, dog } );
Run Code Online (Sandbox Code Playgroud)
为了避免这里的冗长的唯一方法是有foo
取std::array
作为参数.这意味着它只能采用特定固定大小的数组.你不能使用C++ 14的提议dynarray
,因为那将使用initializer_list
中介.
最终,您不应该使用统一的初始化语法来传递值列表.它用于初始化对象,而不是用于传递事物列表.std::initializer_list
是一个类,其唯一目的是用于从相同类型的任意长的值列表中初始化特定对象.它用作语言构造(braced-init-list)和构造函数之间的中间对象,这些构造函数将被输入.它允许编译器initializer_list
在给定匹配的braced-init-values值列表时知道调用特定的构造函数(构造函数).
这就是课程存在的全部原因.
因此,您应该将该类专门用于其设计目的.该类存在于将构造函数标记为从braced-init-list中获取值列表.因此,您应该仅将它用于具有此值的构造函数.
如果您有一些函数foo
充当某个内部类型(您不想直接公开)和用户提供的值列表之间的中介,那么您需要将其他内容作为参数foo
.具有您想要的语义的东西,然后您可以将其输入您的内部类型.
而且,你似乎对initializer_list
s和运动有误解.您不能移动出来的initializer_list
,但你肯定可以移动到一个:
foo( { "blah", 3, std::move(dog) } );
Run Code Online (Sandbox Code Playgroud)
内部dog
数组中的第三个条目将是移动构造的.