Clang ++ fails, but g ++ succeeds when using cast-const-unrelated-type operator in assignment

Here is a brief example that reproduces this β€œno viable conversion” with lemon for clang, but valid for g ++ differences in compiler behavior.

#include <iostream> struct A { int i; }; #ifndef UNSCREW_CLANG using cast_type = const A; #else using cast_type = A; #endif struct B { operator cast_type () const { return A{i}; } int i; }; int main () { A a{0}; B b{1}; #ifndef CLANG_WORKAROUND a = b; #else a = b.operator cast_type (); #endif std::cout << ai << std::endl; return EXIT_SUCCESS; } 

live on godbolt

g ++ (4.9, 5.2) compiles this silently; whereas clang ++ (3.5, 3.7) compiles it

if a

 using cast_type = A; 

or

 using cast_type = const A; // [...] a = b.operator cast_type (); 

, but not with default

 using cast_type = const A; // [...] a = b; 

In this case, clang ++ (3.5) blames a = b :

 testling.c++:25:9: error: no viable conversion from 'B' to 'A' a = b; ^ testling.c++:3:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'B' to 'const A &' for 1st argument struct A { ^ testling.c++:3:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'B' to 'A &&' for 1st argument struct A { ^ testling.c++:14:5: note: candidate function operator cast_type () const { ^ testling.c++:3:8: note: passing argument to parameter here struct A { 

Regarding the 2011ΒΉ standard: Does clang ++ correctly say that it refuses to use default code, or does it agree with g ++ correctly?

Nota bene . This is not a question of whether const classifier on cast_type makes sense. It is about which compiler works standardly and only about that .

No. 2014 should not be of any significance here.

EDIT:

Please refrain from re-tagging this with a generic C ++ tag. First, I would like to know what behavior complies with the 2011 standard, and to maintain the commitment of the not to break existing (< 2011) code committees from the ansatz for now.

+8
language-lawyer c ++ 11 g ++ clang ++ conversion-operator
source share
1 answer

So it looks like this is covered by this error message clang rvalue overload hides const lvalue one? which has the following example:

 struct A{}; struct B{operator const A()const;}; void f(A const&); #ifdef ERR void f(A&&); #endif int main(){ B a; f(a); } 

which fails with the same error as the OP code. Richard Smith at the end says:

Update: we correctly selected 'f (A & &)', but we are mistaken to reject parameter initialization. Further reduction:

  struct A {}; struct B { operator const A(); } b; A &&a = b; 

Here [dcl.init.ref] p5 bullet 2 bullet 1 bullet 2 is not applied because [over.match.ref] p1 does not find the candidate conversion function because "A" is not a reference to "const A". So, we drop into [dcl.init.ref] p5 bullet 2 bullet 2 and copy-initialize the temporary type A from 'b' and bind the link to it. I am not, of course, in this process we are mistaken.

but then returns with another comment due to 1604 defect report :

DR1604 changed the rules to

  A &&a = b; 

now badly formed. Therefore, we are now right to reject initialization. But this is still a terrible answer; I pushed the CWG again. We should probably discard f (A & &) while resolving congestion.

So, it seems that clang is technically correct, based on the standard language today, but could change, because there seems to be a disagreement, at least from the clang team, that this is the correct result. Therefore, presumably this will lead to a defect report, and we will have to wait until it is resolved before we can reach a final conclusion.

Refresh

Looks like a 2077 bug report was filed based on this issue.

+8
source share

All Articles