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'