[cfe-dev] Strange phenomenon with conversion operator and call of overloaded method

Johannes Schaub (litb) schaub.johannes at googlemail.com
Thu Jun 2 04:30:27 PDT 2011


Jonathan Sauer wrote:

> Hello,
> 
> thank you for your (as always) detailed answer!
> 
>>> struct Foo { };     // (A)
>>> //using Foo = int;    // (B)
>>> 
>>> template <typename T>
>>> class A {
>>>    public:
>>>        operator const T&() const { return m_t; }
>>> 
>>>    private:
>>>        T   m_t;
>>> };
>>> 
>>> static void bar(Foo&&) { }  // (C)
>>> static void bar(const Foo&) { }
>>> 
>>> int main(int, char**)
>>> {
>>>    A<Foo>              a;
>>>    bar(a);
>>>    bar((const Foo&) a);  // (D)
>>> }
>> 
>> You can interpret the spec so that it yields exactly clang's behavior, I
>> think. The spec says that for a reference binding of "Foo&&" to "A<Foo>",
>> the following conversion functions are candidates (S is the initializer,
>> A<Foo>, and T is the type "Foo"):
>> 
>> "Those that are not hidden within S and yield type “lvalue reference to
>> cv2 T2” (when 8.5.3 requires an lvalue result) or “cv2 T2” or “rvalue
>> reference to cv2 T2” (when 8.5.3 requires an rvalue result), where “cv1
>> T” is reference-compatible (8.5.3) with “cv2 T2”, are candidate
>> functions."
>> 
>> This reads to me that "operator const T&" is *not* a candidate here,
>> because "const T&" is an lvalue reference. However, the example in 8.5.3
>> indicates that the intent seems that we *do* consider "operator const T&"
>> as a candidate. Consider the similar example it gives at 8.5.3:
>> 
>> struct X {
>> operator B();
>> operator int&();
>> } x;
>> 
>> int &&rri2 = X(); // ill-formed: lvalue-to-rvalue conversion on result of
>> operator int&
> 
> I agree with this reading. In 8.5.3p5, a bit above the example you posted,
> is an example that is not ill-formed:
> 
> struct A { };
> struct B : A { operator int&(); } b;
> 
> int& ir = B(); // ir refers to the result of B::operator int&
> 

I'm now more confident than before that the description at 8.5.3 about an 
lvalue to rvalue conversion happening as the second standard conversion 
sequence in the user defined conversion sequence is not correct. The 
description of the user defined conversion sequence at 13.3.3.1.4p1 says 
(note that this is a "direct binding" according to 8.5.3):

"If the parameter binds directly to the result of applying a conversion 
function to the argument expression, the implicit conversion sequence is a 
user-defined conversion sequence (13.3.3.1.2), with the second standard 
conversion sequence either an identity conversion or, if the conversion 
function returns an entity of a type that is a derived class of the 
parameter type, a derived-to-base Conversion"

Hence, there simply cannot be an lvalue to rvalue conversion in that user 
defined conversion sequence. By that text, the user defined conversion 
sequence is an identity conversion. So, by 13.3.3.1.4p1, this would be a 
case where a standard conversion sequence (the second one of our UCS) would 
require binding an rvalue reference to an lvalue (because by 13.3.3.1.4, 
there is no lvalue to rvalue conversion, at least not for the purpose of 
constructing an implicit conversion sequence). Such a conversion sequence 
cannot exist by 13.3.3.1.4p3, and hence the whole user defined conversion 
sequence cannot exist, and the description and example in 8.5.3p5 seems to 
be defective (I suspected this earlier from the sight of 13.3.1.6, but now 
we have another paragraph that seem to contradict 8.5.3p5).

>> So assuming that clang follows this intent, we would have it choose
>> "operator const T&" as a candidate conversion function, and (because we
>> are initializing an rvalue reference), will do an lvalue to rvalue
>> conversion on the lvalue it yields (according to 3.10p2).
> 
> I don't quite understand. Why would we need to do a conversion from lvalue
> to rvalue here? Just because the first bar method takes an rvalue
> reference?
> 

I have no idea anymore. I prefer to not base my argument on 8.5.3 anymore, 
unless someone that has more insight into the intention behind 8.5.3 speaks 
up and clarifies that for us. I may be missing something really important 
here.





More information about the cfe-dev mailing list