This C++ code doesn't look ambiguous to me
Look at this C++ code:
test.cpp
class B;
class A { public: A (B&);};
class B { public: operator A(); };
class C { public: C (B&); };
void f(A) { }
void f(C) { }
int main() {
B b;
f(b);
}
Do you think this compiles? Well, probably not because I’m asking. So here’s the error message from Clang 13:
etyp:fun/ $ clang++ test.cpp
test.cpp:10:3: error: call to 'f' is ambiguous
f(b);
^
test.cpp:5:6: note: candidate function
void f(A) { }
^
test.cpp:6:6: note: candidate function
void f(C) { }
^
1 error generated.
Okay so it’s ambiguous which conversion gets done for the object b
(of type B
). So what options are there?
1) Call f(A)
. We can call A
’s constructor which takes a reference to a B
2) Call f(C)
. We can call C
’s constructor which takes a reference to a B
3) Call f(A)
. We can call operator A()
in the class B
But, 1 and 3 are ambiguous because we can’t find a better one to call f(A)
. But f(C)
is still not ambiguous - we know how to call it without any ambiguity. Trying to call f(A)
is ambiguous so obviously it shouldn’t be chosen.
It turns out in this case, the ambiguity between 1 and 3 is ranked equal priority as the user defined conversion in 2. From the C++20 standard section 12.4.2.10:
For the purpose of ranking implicit conversion sequences as described in 12.4.3.2, the ambiguous conversion sequence is treated as a user-defined conversion sequence that is indistinguishable from any other user-defined conversion sequence.
I find this surprising because I could easily determine that option 2 is the unambiguous way to make this compile.
Not all compilers…
It turns out, MSVC actually accepts the code. You can even see in the assembly it calls f(C)
.
I believe no matter how silly the standard is with its rules (which this particular point may have a very good reason), C++ compilers should aim to conform to the standard. This case was pulled exactly from the standard as a case that should not compile. MSVC should not compile this.
But that’s a whole other rant.
Thanks for looking at that C++ code.