4
votes

I am running into a compiler issue when using map class, and wrote the following simple program to highlight the error:

  1 #include <string>
  2 #include <map>
  3
  4 using namespace std;
  5
  6 int main()
  7 {
  8     map<string, string> testmap;
  9
 10
 11     testmap["one"] = 11;
 12     testmap["two"] = 22;
 13     testmap["zero"] = 0;
 14     // testmap["zero"] = 10;
 15
 16     return 0;
 17 }

I get the following compilation error:

g++ ./test.cc ./test.cc: In function 'int main()': ./test.cc:13:23: error: ambiguous overload for 'operator=' in 'testmap.std::map<_Key, _Tp, _Compare, _Alloc>::operator[], std::basic_string, std::less >, >std::allocator, std::basic_string > > >((* & std::basic_string(((const char*)"zero"), ((const std::allocator)(& std::allocator()))))) = 0' ./test.cc:13:23: note: candidates are: In file included from /usr/include/c++/4.7/string:54:0, from ./test.cc:1: /usr/include/c++/4.7/bits/basic_string.h:543:7: note: std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(const std::basic_string<_CharT, _Traits, _Alloc>&) [with >_CharT = char; _Traits = std::char_traits; _Alloc = std::allocator; std::basic_string<_CharT, _Traits, _Alloc> = std::basic_string] /usr/include/c++/4.7/bits/basic_string.h:551:7: note: std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(const _CharT*) [with _CharT = char; _Traits = >std::char_traits; _Alloc = std::allocator; std::basic_string<_CharT, _Traits, _Alloc> = std::basic_string] /usr/include/c++/4.7/bits/basic_string.h:562:7: note: std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(_CharT) [with _CharT = char; _Traits = std::char_traits; _Alloc = std::allocator; std::basic_string<_CharT, _Traits, _Alloc> = std::basic_string]

I have a few questions: 1. Initially I thought the map "values" - 11 and 22 were being converted to string. However, after getting this compiler error makes me believe otherwise. What is exactly happening under the hood in the following: testmap["one"] = 11;

  1. If the values 11, 22 is in fact converted to string, then why is 0 not converted to a string.

  2. I am trying hard to understand the compiler error message, so I can decode the error myself. I understand parts of it, where the template map class definition is expanded with the key/value being of type string. Can someone please point me to the parts of the error message that may help me understand the issue.

Any help is much appreciated.

Thank you, Ahmed.

1
You can assign a character to a string, and you can assign a pointer. 0 qualifies for both.chris

1 Answers

13
votes

If the values 11, 22 is in fact converted to string, then why is 0 not converted to a string.

They're not. Your 11 and 12 assignments are matching basic_string& operator=( CharT ch ); - so it's treating the numbers 11 and 12 as character constants - presumably not what you wanted. Say you sent them to a terminal or printer ala std::cout << testmap["one"]; - 11 corresponds to a "Vertical Tab" control code which might leave some blank lines, and 12 to "Form Feed" which might leave the rest of a printed page blank or clear the screen (see http://en.wikipedia.org/wiki/ASCII).

0 is special in the sense that it's allowed to be implicitly converted to a pointer (in C++03 NULL would be defined as 0), and for that reason the conversion is ambiguous (i.e. char or const char*?) - see http://en.cppreference.com/w/cpp/string/basic_string/operator%3D for a list of the std::string operator=s.

4.10 Pointer conversions [conv.ptr] 1 A null pointer constant is an integer literal (2.14.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; ...

Other integers don't have this pointer conversion dispensation - that's why you're not getting compiler errors for them.

You must either:

  • properly convert your numbers to string representation, e.g. using std::to_string(), boost::lexical_cast, a std::ostringstream etc.., or
  • use a std::map<string, int> or similar instead.