Am I allowed to move elements out of 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?
}
}
Since std::intializer_list<T>
requires special compiler attention and does not have value semantics like normal containers of the C++ standard library, I'd rather be safe than sorry and ask.
Best Answer
No, that won't work as intended; you will still get copies. I'm pretty surprised by this, as I'd thought that
initializer_list
existed to keep an array of temporaries until they weremove
'd.begin
andend
forinitializer_list
returnconst T *
, so the result ofmove
in your code isT const &&
— an immutable rvalue reference. Such an expression can't meaningfully be moved from. It will bind to an function parameter of typeT const &
because rvalues do bind to const lvalue references, and you will still see copy semantics.Probably the reason for this is so the compiler can elect to make the
initializer_list
a statically-initialized constant, but it seems it would be cleaner to make its typeinitializer_list
orconst initializer_list
at the compiler's discretion, so the user doesn't know whether to expect aconst
or mutable result frombegin
andend
. But that's just my gut feeling, probably there's a good reason I'm wrong.Update: I've written an ISO proposal for
initializer_list
support of move-only types. It's only a first draft, and it's not implemented anywhere yet, but you can see it for more analysis of the problem.