#include <iostream>
struct B;
struct A{
operator B&&() const;
};
struct B{
B(A const&){
}
B() {}
};
int main(){
A a;
B&& rf = a; //#1
}
B g;
A::operator B&&() const {
std::cout<<"execute\n";
return std::move(g);
}
Consider the above code, The outcome is here. The reference binding at #1
subject to these rules:
Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference.
- If the initializer expression
- is an rvalue (but not a bit-field) or function lvalue and “cv1 T1” is reference-compatible with “cv2 T2”, or
- has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be converted to an rvalue or function lvalue of type “cv3 T3”, where “cv1 T1” is reference-compatible with “cv3 T3” (see [over.match.ref]),
then the value of the initializer expression in the first case and the result of the conversion in the second case is called the converted initializer. If the converted initializer is a prvalue, its type T4 is adjusted to type “cv1 T4” ([conv.qual]) and the temporary materialization conversion is applied. In any case, the reference is bound to the resulting glvalue (or to an appropriate base class subobject).
- Otherwise:
- If T1 or T2 is a class type and T1 is not reference-related to T2, user-defined conversions are considered using the rules for copy-initialization of an object of type “cv1 T1” by user-defined conversion ([dcl.init], [over.match.copy], [over.match.conv]); the program is ill-formed if the corresponding non-reference copy-initialization would be ill-formed. The result of the call to the conversion function, as described for the non-reference copy-initialization, is then used to direct-initialize the reference. For this direct-initialization, user-defined conversions are not considered.
According to the structure of the above rules, The second bullet of the If
branch is sufficient for B&& rf = a;
, hence operator B&&() const
of class A
is the unique candidate conversion function, In other words, as long as the if
case be satisfied, then the branch of otherwise
will never under go.
The outcome of GCC
evidence what these rules says, however Clang
complain the conversion function for performing reference binding are ambiguous(Clang
seems to consider both conversion functions in respectively branch as candidate functions). Is it a bug in clang?
Even though, such case
#include <iostream>
struct B;
struct A{
operator B&&() const;
};
struct B{
B(A&){
}
B() {}
};
int main(){
A a;
B&& rf = a; //#1
}
B g;
A::operator B&&() const {
std::cout<<"execute\n";
return std::move(g);
}
GCC
still agree operator B&&() const
is the unique conversion function for performing reference binding.