Q:

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

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 <iostream>

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

A:

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.

