I commonly use std::initializer_list<std::string>
, say {"foo"s, "bar"s}
, to fill a container.
Obviously, std::initializer_list<std::string>
contains temporary strings, and I can move them into a container:
#include <string>
#include <list>
using namespace std::literals;
void f(std::initializer_list<std::string> il)
{
std::list<std::string> coll;
for (auto&& tmp_str : il)
{
coll.emplace_back(std::move(tmp_str)); // Why ok here?
}
}
int main()
{
f({"foo"s, "bar"s});
}
However, according to cppref:
An object of type std::initializer_list is a lightweight proxy object that provides access to an array of objects of type const T.
Why does C++ make the element type of std::initializer_list const?
Obviously,
std::initializer_list<std::string>
contains temporary strings
Does it, though? It is allowed to be implemented it as a thin proxy. In which case it would refer to the original instances "foo"s
, "bar"s
.
... and I can move them into a container
I doubt that. std::move()
of a const
lvalue-reference produces... a const
rvalue-reference. That won't quite match a move-constructor as a viable candidate.
#include <iostream>
struct A {
A() { std::cout << "A()\n"; }
A(A&&) { std::cout << "A(&&)\n"; }
A(A const&) { std::cout << "A(const&)\n"; }
};
int main() {
const A a;
A b(std::move(a));
}
Prints
A()
A(const&)
MSVC 2019 even warns:
Warning C26478 Don't use std::move on constant variables. (es.56).