编辑:在我们开始之前,这个问题不涉及std::initializer_list
的正确使用方法;而是关于在需要方便的语法时应传递什么内容。感谢您保持主题。
C++11引入了std::initializer_list
用于定义接受花括号初始化列表参数的函数。
struct bar {
bar( char const * );
bar( int );
} dog( 42 );
fn foo( std::initializer_list< bar > args );
foo( { "blah", 3, dog } );
这种语法很不错,但底层实现由于多种问题而不尽人意:
它们不能被有意义地移动。上面的函数必须从列表中复制
dog
;这不能转换为移动构造或省略。只能使用移动语义的类型完全无法使用。(嗯,const_cast
实际上是一个有效的解决方法。如果有关于这样做的文章,我想看看。)也没有
constexpr
语义。(在C++1y中即将推出。虽然这只是一个小问题。)const
不能像其他地方一样传播;initializer_list
从来不是const
,但其内容总是如此。(因为它不拥有其内容,所以它不能给予副本写入访问权限,尽管将其复制到任何位置都很少安全。)initializer_list
对象不拥有其存储空间(哎呀); 它与提供存储空间的完全独立的裸数组(哎呀)之间的关系定义得模糊不清(哎呀),就像引用与绑定临时变量的关系一样(四重哎呀)。
我相信这些问题将在适当的时候得到解决,但现在有没有一种最佳实践可以在不硬编码到initializer_list
中的情况下获得优点?是否有任何关于绕过对其直接依赖的文献或分析?
明显的解决方案是传递一个标准容器(例如std::vector
)的值。一旦从initializer_list
中复制对象到它中,它就被移动构造为按值传递,然后你就可以移动内容了。改进方法是在栈上提供存储空间。一个好的库可能能够在不使用前者的情况下提供大部分initializer_list
,array
和vector
的优势。
有什么资源可参考吗?
foo
需要使用初始化列表。它不是一个容器;这正是您所链接的答案试图提醒您的内容。如果您想要一个数组,那就不同于想要一个初始化列表。 - Nicol Bolasfoo
要采用初始化列表。对我来说,唯一应该采用带有std::initializer_list
参数的函数类型是对象的构造函数。所有其他函数都应该采用具有实际语义的容器形式。” - Nicol Bolasstd::move
来调用它。 - Nicol Bolasmove
是没有意义的。 - Potatoswatter