Wednesday, 11 October 2017

c++ - Is MSVC right to find this method call ambiguous, whilst Clang/GCC don't?

itemprop="text">

Clang (3.9.1) and GCC (7, snapshot)
print "1", "2" to the console when this code is
run.



However, MSVC fails to compile this
code:






source_file.cpp(15): error C2668: 'Dictionary::set': ambiguous call to
overloaded function



source_file.cpp(9): note:
could be 'void Dictionary::set(int64_t)'




source_file.cpp(8): note: or 'void Dictionary::set(const char
*)'



source_file.cpp(15): note: while trying to
match the argument list '(const unsigned
int)'





#include


static const unsigned ProtocolMajorVersion =
1;
static const unsigned ProtocolMinorVersion = 0;

class
Dictionary {
public:
void set(const char *Str) { std::cout <<
"1"; }
void set(int64_t val) { std::cout << "2";
}

};

int main() {
Dictionary
dict;
dict.set(ProtocolMajorVersion);

dict.set(ProtocolMinorVersion);
}


I
think MSVC is right - the value of ProtocolMajorVersion is
0, which can be NULL or
int64_t(0).




However,
this seems to be the case when
replacing



dict.set(ProtocolMinorVersion)


with



dict.set(0);





source_file.cpp:15:10: error: call to member function 'set' is
ambiguous
dict.set(0);




source_file.cpp:8:10: note: candidate
function



void set(const char *Str)
{ std::cout << "1"; }




source_file.cpp:9:10: note: candidate
function



void set(int64_t val) {
std::cout << "2";
}



So
what's going on here - which compiler is right? Would surprise me if both GCC and Clang
are accepting incorrect code, or is MSVC just being buggy? Please refer to the
standard



Answer




In C++11 and before, any integral
constant expression
which evaluates to 0 is a considered a null
pointer constant
. This has been restricted in C++14: only integer literals
with value 0 are considered. In addition, prvalues of type
std::nullptr_t are null pointer constants since C++11. See
[conv.ptr] and CWG
903
.




Regarding overload
resolution, both the integral conversion unsigned ->
int64_t and the pointer conversion null pointer
constant
-> const char* have the same rank:
Conversion. See [over.ics.scs] / Table 12.



So if
ProtocolMinorVersion is considered a null pointer constant,
then the calls are ambiguous. If you just compile the following
program:



static const unsigned
ProtocolMinorVersion = 0;

int main() {
const char* p =
ProtocolMinorVersion;
}



You
will see that clang and gcc reject this conversion, whereas MSVC accepts
it.



Since CWG 903 is considered a defect, I'd
argue that clang and gcc are right.


No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print ...