Search code examples
c++c++11gccautoc++17

Auto declaration of map iterator error on GCC


I have a map defined as:

std::map<unsigned int, std::string> spCalls;  

I also have a function that returns the string, given the key. It is defined as:

std::string spGetCallString(unsigned int key)
{
    auto iter{ spCalls.find(key) };

    return iter->second;
}

When attempting to compile this, with GCC, I get an error which says

error: base operand of '->' has non-pointer type
'std::initializer_list < std::_Rb_tree_iterator < std::pair < const unsigned int, std::basic_string < char> > > >'

 return iter->second;"

I just cannot make any sense of this and I can't see why my code shouldn't work. I appreciate any help.


Solution

  • Before C++17, auto type deduction for braced initializer will always yield type of instantiation of std::initializer_list, so for auto iter{ spCalls.find(key) };, the type of iter would be std::initializer_list<std::map<unsigned int, std::string>::iterator>, which doesn't match the usage at all.

    Since C++17 you'll get the correct type for it, i.e. std::map<unsigned int, std::string>::iterator.

    In direct-list-initialization (but not in copy-list-initalization), when deducing the meaning of the auto from a braced-init-list, the braced-init-list must contain only one element, and the type of auto will be the type of that element:

    auto x1 = {3}; // x1 is std::initializer_list<int>
    auto x2{1, 2}; // error: not a single element
    auto x3{3};    // x3 is int (before C++17 it was std::initializer_list<int>)
    

    If your compiler still doesn't support that, you could change braced initializer to other initializers, e.g.

    auto iter = spCalls.find(key);
    auto iter(spCalls.find(key));