The following code compiles fine with g++ (GCC) 4.7.1 20120721, but
fails with a recently build clang version 3.2 (trunk).
struct Y {};
struct X {
operator const Y() const { return Y(); }
};
void f(Y&& y) {}
int main()
{
f(X());
return 0;
}
Changing the conversion operator to operator Y() const is sufficient
to make the code compile on both compilers.
Which compiler is actually standard compliant in this case? What does
the standard actually say about this?
The verbatim error as requested:
bla.cpp:14:5: error: no viable conversion from 'X' to 'Y'
f(X());
^~~
bla.cpp:1:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'X' to
'const Y &' for 1st argument
struct Y {
^
bla.cpp:1:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'X' to
'Y &&' for 1st argument
struct Y {
^
bla.cpp:6:3: note: candidate function
operator const Y() const { return Y(); }
^
bla.cpp:10:12: note: passing argument to parameter 'y' here
void f(Y&& y) {}
^
EDIT: Unfortunately even adding the overload
void f(const Y&) {}
still makes clang choose the rvalue reference overload and so this
breaks existing code that used to compile fine, e.g. with standard
containers.
I believe clang is right to reject this. Passing the argument to
f(Y&&)requires two conversion steps, the first being youroperator const Y()and the second beingY‘s copy constructor. Both count as user-defined conversions, I think, and both are implicit, which violates the principle that an implicit conversion sequence only includes one user-defined conversion.This Purpose of returning by const value? contains some interesting insights into the semantics of returning a
const T.Hm, if I try adding an overload
void f(const Y&y)as the edited question now does, clang behaves pretty strangly. It still complains about being unable to convertXtoY, and doesn’t even list the overloadf(const Y& y)in its diagnostic. But once I change the overload to takeYby value, i.e. writevoid f(const Y y), it complains about the call tofbeing ambiguous.This is with XCode 4.5’s clang which reports
Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn). If you can reproduce this with a vanilla clang, you should probably report this on the clang mailing list – sure seems to there’s a bug lurking there somewhere…