Search code examples
c++11c-stringsinitializer-list

Creating std::initializer_list Constructor for c-style strings


I was creating a Graph program for college, and had created an std::initializer_list constructor for the graph, like so:

Graph(std::initializer_list< std::string >& _vertices_){
    // ... initialising my map of vertices with their names
}

However, when I tried to initialise the Graph in my main program:

int main(){
    Graph g = { "A", "B", "C", "D", "F", "G" };        //Error: Does not compile
    g.connectEdge( "A", "B" ).setWeight( 2 );
    // ... connecting other edges
    g.set_path_algorithm( Graph::DJIKSTRA );
    int cost = g.find_shortest< Graph::COST >("A", "G");
    //int hops = g.find_shortest< Graph::HOPS >("A", "G");
    std::cout << "The shortest path between A and G is: " << cost ;
    return 0;
}

I get:

test_djikstra.cpp: In function 'int main()':
test_djikstra.cpp:36:46: error: could not convert '{"A", "B", "C", "D", "F", "G"}' from '<brace-enclosed initializer list>' to 'Graph'
     Graph g = { "A", "B", "C", "D", "F", "G" };
                                              ^

Now, when I create a constructor that takes a std::string and pass a c-style string
(const char []), the function to convert it to std::string is automatically called.

Why does this not convert each const char [] parameter to std::string?

What is the issue, and what are it's possible solutions?

Edit: So I was creating a reference to a temporary object. Subtle! Thanks @rafix07.


Solution

  • This

    { "A", "B", "C", "D", "F", "G" }
    

    creates initializer list object. It is temporary instance. Temporary object cannot be bound to Lvalue reference.

    Solutions:

    [1] make const reference

    Graph(const std::initializer_list< std::string >& _vertices_)
    

    [2] just discard reference

    Graph(std::initializer_list< std::string > _vertices_)
    

    Initializer list is lightweight object (can be treated as pair: pointer to data + length), so copying of it is not expensive.