There is no way to avoid the copying from an initializer_list<string>
, because the standard defines the invocation of a constructor taking an initializer list argument, from a curly braces initializer as actual argument, as follows (emphasis added):
C++14 §8.5.4/5
” An object of type std::initializer_list<E>
is constructed from an initializer list as if the implementation allocated a temporary array of N
elements of type const E
, where N
is the number of elements in the
initializer list
IMHO this is really unfortunate.
A workaround (for your own classes) is to accept initializer_list<char const*>
.
Here's an example of the workaround applied to std::vector<string>
. For that, where you don't control the class' code, it involves declaring a data array (actually an initializer_list
) explicitly. This is just as with C++03, which the initializer list mechanism was intended to avoid:
#include <vector>
#include <initializer_list>
#include <iostream>
#include <iterator> // std::begin, std::end
using namespace std;
struct My_string
{
char const* const ps;
My_string( char const* const s )
: ps( s )
{
cout << " My_string(*) <- '" << s << "'" << endl;
}
My_string( My_string const& other )
: ps( other.ps )
{
cout << " My_string(const&) <- '" << other.ps << "'" << endl;
};
My_string( My_string&& other )
: ps( other.ps )
{
cout << " My_string(&&) <- '" << other.ps << "'" << endl;
};
};
auto main() -> int
{
cout << "Making vector a." << endl;
vector<My_string> const a = {"a1", "a2", "a3"};
cout << "Making data for vector b." << endl;
auto const b_data = { "b1", "b2", "b3" };
cout << "Making vector b." << endl;
vector<My_string> const b( begin( b_data ), end( b_data ) );
}
Output:
Making vector a.
My_string(*) <- 'a1'
My_string(*) <- 'a2'
My_string(*) <- 'a3'
My_string(const&) <- 'a1'
My_string(const&) <- 'a2'
My_string(const&) <- 'a3'
Making data for vector b.
Making vector b.
My_string(*) <- 'b1'
My_string(*) <- 'b2'
My_string(*) <- 'b3'