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.
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 were move'd.
begin and end for initializer_list return const T *, so the result of move in your code is T const && — an immutable rvalue reference. Such an expression can't meaningfully be moved from. It will bind to an function parameter of type T 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 type initializer_list or const initializer_list at the compiler's discretion, so the user doesn't know whether to expect a const or mutable result from begin and end. 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With