inicializador_lista y semántica de movimiento
¿ Puedo mover elementos fuera de a 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?
}
}
Dado que std::intializer_list<T>
requiere una atención especial del compilador y no tiene una semántica de valor como los contenedores normales de la biblioteca estándar de C++, prefiero prevenir que lamentar y preguntar.
No, eso no funcionará según lo previsto; Aún recibirás copias. Estoy bastante sorprendido por esto, ya que pensé que initializer_list
existía para mantener una variedad de temporales hasta que fueran move
terminados.
begin
y end
para initializer_list
return const T *
, por lo que el resultado de move
su código es T const &&
: una referencia de valor r inmutable. No se puede cambiar significativamente de una expresión así. Se vinculará a un parámetro de función de tipo T const &
porque los valores r se vinculan a referencias de valores l constantes y aún verá la semántica de copia.
Probablemente la razón de esto es que el compilador puede optar por hacer que sea initializer_list
una constante inicializada estáticamente, pero parece que sería más limpio hacer su tipo initializer_list
o const initializer_list
a discreción del compilador, por lo que el usuario no sabe si esperar una variable const
o una variable . resultado de begin
y end
. Pero ese es sólo mi presentimiento, probablemente hay una buena razón por la que estoy equivocado.
Actualización: escribí una propuesta ISO para initializer_list
admitir tipos de solo movimiento. Es sólo un primer borrador y aún no está implementado en ninguna parte, pero puede verlo para analizar más el problema.
bar(std::move(*it)); // kosher?
No de la forma que pretendes. No puedes mover un const
objeto. Y std::initializer_list
solo proporciona const
acceso a sus elementos. Entonces el tipo de it
es const T *
.
Su intento de igualar std::move(*it)
sólo resultará en un valor l. Es decir: una copia.
std::initializer_list
hace referencia a la memoria estática . Para eso es la clase. No se puede mover de la memoria estática, porque el movimiento implica cambiarla. Sólo puedes copiar de él.