Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conversion is ambiguous in Visual Studio 2015, but not with clang

The following code, a simplified version of code found in the googlemock project, fails to compile in Visual Studio 2015 Update 1, but it compiles on clang [Apple LLVM version 7.0.0 (clang-700.1.76)].

struct ConvertibleFromAny {     ConvertibleFromAny(int a_value);      template <typename T>     ConvertibleFromAny(const T& a_value); };  template <typename T> struct Matcher {     Matcher(T value); };  template <typename Rhs> struct EqMatcher {     explicit EqMatcher(const Rhs& rhs);      template <typename Lhs>     operator Matcher<Lhs>() const; };  int main() {     EqMatcher<ConvertibleFromAny> em(1);     Matcher<ConvertibleFromAny> m = em;      return 0; } 

The error occurs at the assignment statement

Matcher<ConvertibleFromAny> m = em; 

and the error message is

error C2440: 'initializing': cannot convert from 'EqMatcher<ConvertibleFromAny>' to 'Matcher<ConvertibleFromAny>' note: No constructor could take the source type, or constructor overload resolution was ambiguous 

I can naively see an ambiguity between a member call to

EqMatcher<ConvertibleFromAny>::operator Matcher<ConvertibleFromAny>() 

and an initialization conceptually similar to

Matcher<ConvertibleFromAny> m(ConvertibleFromAny<EqMatcher<ConvertibleFromAny>>(em)) 

My guess is that clang rules out the second option.

EDIT: Inspired by T.C.'s comment I tested the following:

struct A { };  struct X {     X(const A&); };  struct B {     B(const X&); };  int main() {     A a;      B b = a; } 

It compiles with VS 2015, but not with clang. I have not been able to find any references that documents that the Visual C++ implementation intentionally deviates from the standard in this regard.

Is this a well-known problem?

like image 853
Niels Bliddal Christensen Avatar asked Dec 08 '15 20:12

Niels Bliddal Christensen


Video Answer


1 Answers

Both your code samples produce the expected result with VS2015 Update 1, if I enable the "Disable Language Extensions" (/Za) flag. That is, the first one compiles, the second one does not.

I'm not sure which extension in particular is interfering here, though. I found this MSDN page: Microsoft Extensions to C and C++, but it does not appear to be complete - for example, binding a non-const T& to an rvalue is not mentioned.

like image 92
melak47 Avatar answered Oct 13 '22 20:10

melak47