fre*_*low 88 c++ templates initializer-list move-semantics c++11
我允许将元素移出std::initializer_list<T>?
#include <initializer_list>
#include <utility>
template<typename T>
void foo(std::initializer_list<T> list)
{
for (auto it = list.begin(); it != list.end(); ++it)
{
bar(std::move(*it)); // kosher?
}
}
Run Code Online (Sandbox Code Playgroud)
由于std::intializer_list<T>需要特殊的编译器注意并且没有像C++标准库的普通容器那样的值语义,所以我宁愿安全而不是抱歉并且问.
Pot*_*ter 82
不,这不会按预期工作; 你仍然会得到副本.我对此感到非常惊讶,因为我认为initializer_list存在一系列的临时工,直到他们为止move.
begin并且end对于initializer_listreturn const T *,所以move代码中的结果是T const &&- 一个不可变的右值引用.这样的表达无法有意义地被移除.它将绑定到类型的函数参数,T const &因为rvalues绑定到const左值引用,您仍将看到复制语义.
原因可能是编译器可以选择initializer_list使用静态初始化的常量,但是看起来它的类型initializer_list或const initializer_list编译器可以自行决定是否更清晰,因此用户不知道是期望const还是可变的结果来自begin和end.但这只是我的直觉,可能有一个很好的理由我错了.
更新:我已经编写了ISO提议,以initializer_list支持仅移动类型.它只是初稿,并没有在任何地方实现,但你可以看到它来更多地分析问题.
Nic*_*las 17
bar(std::move(*it)); // kosher?
Run Code Online (Sandbox Code Playgroud)
不是你想要的方式.您无法移动const对象.并且std::initializer_list只提供const对其元素的访问.所以类型it是const T *.
您的通话尝试std::move(*it)只会产生一个l值.IE:副本.
std::initializer_list引用静态内存.这就是班级的用途.你无法从静态内存中移动,因为移动意味着要改变它.您只能从中复制.