سؤال

In the code below, why does the first call resolve to catchClass(aClass&) and given the temporary as a parameter in the second invoke catchClass(const aClassCatcher&)

#include <iostream>

using namespace std;

class aClassCatcher{};

class aClass{
public:
    operator aClassCatcher(){
        return aClassCatcher();
    }
};

void catchClass(aClass&){
    cout << __FUNCSIG__ << endl;
}
void catchClass(const aClassCatcher&){
    cout << __FUNCSIG__ << endl;
}

int main()
{
    aClass aC;
    catchClass(aC); // calls catchClass(aClass&)

    catchClass(aClass()); // calls catchClass(const aClassCatcher&)

}

In case you are wondering where I came upon this, I am trying to understand move constructors as described in an article at Dobb's.

هل كانت مفيدة؟

المحلول

First of all, it is important to notice that the behavior you are observing is not related to move semantics, nor to the presence or absence of a move constructor. You could run your example on a C++03 compiler and observe the exact identical behavior.

The explanation for the behavior you are observing is that lvalue references to non-const (aClass&) can only bind to lvalues, while lvalue references to const (const aClassCatcher&) can bind both to lvalues and to rvalues (but do not allow modifying the object they are bound to, since they are references to const).

If you are working with Microsoft's VC compiler, that may sound strange to you. The reason is the MSVC has a non-Standard extension which allows binding rvalues to lvalue references to non-const. This is IMO a bad extension, and that's not how Standard C++ works.

Now this said, when you provide a temporary, which is an rvalue, the compiler has no chance but picking the overload that takes an lvalue reference to const. The overload taking an lvalue reference to non-const is simply not viable, because of what I previously wrote.

Now in your case, the second overload is viable because there is a user-defined conversion from aClass to aClassCatcher. That conversion will return a temporary of type aClassCatcher, and lvalue references to const can bind to temporaries. Therefore, your second overload is picked.

When you provide an lvalue, on the other hand, both overloads are viable, but the one accepting an lvalue reference to non-const is preferred because no conversion is needed.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top