Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"C2593: operator = is ambiguous" when populating std::map

Tags:

c++

c++11

I have a std::map I'm trying to initialize with an initialization list. I do this in two places, in two different ways. The first one works, while the other one causes the error mentioned in the title.

Here's the one that works:

void foo() {
    static std::map<std::string, std::string> fooMap =
    {
        { "First", "ABC" },
        { "Second", "DEF" }
    };
}

While this one does not:

class Bar {
    public:
        Bar();
    private:
        std::map<std::string, std::string> barMap;
};

Bar::Bar() {
    barMap = { // <-- this is the error line
        { "First", "ABC" },
        { "Second", "DEF" }
    };
}

Why do I get the error when trying to initialize the class member, while the static map works? At the moment, I can populate the member by first creating a local variable and then swapping it with the member like this:

Bar::Bar() {
    std::map<std::string, std::string> tmpMap = {
        { "First", "ABC" },
        { "Second", "DEF" }
    };

    barMap.swap(tmpMap);
}

However, this feels rather counter-intuitive compared to just populating the member directly.


EDIT: Here's the compiler output.

like image 827
manabreak Avatar asked Oct 23 '14 08:10

manabreak


1 Answers

This is a bug in your compilers overload resolution mechanism - or its standard library implementation. Overload resolution clearly states in [over.ics.rank]/3 that

— List-initialization sequence L1 is a better conversion sequence than list-initialization sequence L2 if L1 converts to std::initializer_list<X> for some X and L2 does not.

Here, X is std::pair<std::string, std::string>. L1 converts your list to the parameter of

map& operator=( std::initializer_list<value_type> ilist );

Whilst L2 converts the list to one of the following functions' parameters:

map& operator=( map&& other );
map& operator=( const map& other );

Which clearly aren't initializer_lists.


You could try to use
barMap = decltype(barMap){
    { "First", "ABC" },
    { "Second", "DEF" }
};

Which should select the move-assignment operator (Demo with VC++). The temporary should also be optimized away according to copy elision.

like image 139
Columbo Avatar answered Oct 14 '22 05:10

Columbo