Platform dependend overload resolution ambiguity
Here I will show case when types used internally by compiler might cause ambiguities in overload resolution. Below is example code:
#include <string> struct CoolString { std::string s; CoolString(const char* p) : s(p){} char& operator[](size_t i) { return s.at(i); } operator char*() { return &s[0]; } }; int main() { CoolString ss("asd"); ss[1] = '1'; // {1} }
It looks valid, althought use of implicit user conversion operator to char* is a sign of bad design (std::string provides c_str instead). Above code compiles under g++ and clang, but fails to compile under Visual Studio. The error is that call {1} is ambiguous, and looks like below:
2>c:\prj\test.cpp(10) : error C2666: 'CoolString::operator []' : 2 overloads have similar conversions 2> c:\prj\test.cpp(10): could be 'char &CoolString::operator [](size_t)' 2> or 'built-in C++ operator[(char *, int)' 2> while trying to match the argument list '(CoolString, int)'
so, compiler is unable to decide which one of those to choose:
ss.operator[](1) // line 1 ss.operator char*()[1] // line 2
In case of second choice ( line 2 ), compiler wants to apply built in subscript operator after user defined conversion to char*. Built in subscript operator takes index as a ptrdiff_t type. Because this is a typedef, lets check how it differs under g++/clang from VS:
std::cout << "size_t = " << typeid(size_t).name() << std::endl; // VS2013: unsigned int, g++: unsigned long std::cout << "ptrdiff_t = " << typeid(ptrdiff_t).name() << std::endl; // VS2013: int, g++: long
Under VS ptrdiff_t is int, while under g++/clang its long. While size_t is always unsigned. Lets look what conversions are required by both candidates:
ss.operator[](1) – here only integral promotion of int to unsigned int or unsigned long is required
ss.operator char*()[1] – here on VS only user defined conversion must be applied to ss (so that operator char*() is called), since 1 is an int it matches ptrdiff_t which under VS is also int. But under g++/clang two conversions are requried: first user defined to char*, and then promotion of int to long.
Now its clear why VS shows error, implicit conversions sequences are ambiguous – both are of same lenghts, also they differ on different positions, but I am not clear about it here (exact standard wording) – you could argue that integral promotion should be more promoted than user defined conversion.
Under g++/clang built in operator is not choosen because it requires two implicit conversions, first is user defined conversion, second is promotion int to long. So compiler choses ss.operator[](1) which requires only integral promotion.
The solution is to:
1. Dont use implicit conversion operator to char*
2. Replace size_t with int in char& operator[](size_t i), this will make it a perfect match and top priority candidate.
3. Use ss[1u]
For more references:
– http://stackoverflow.com/questions/1726740/c-error-operator-2-overloads-have-similar-conversions
– “C++ Templates – The Complete Guide” – B.2.1
Leave a Reply