3

While answering this question I came across an interesting difference in the overload resolution of rvalue to reference between member and non-member operators.

Given two non-member operators, one passing the left parameter as const and one as non-const, both GCC 4.4.3 and MSVC2010 choose the const version when called with an rvalue.

However, given two member operators, one const and one non-const, both compilers choose the non-const version.

I assume that both compilers are complying with the standard on this, so I am curious as to why there is this discrepancy between const overload resolution between members and non-members. Please enlighten me :)

Here's some code to illustrate the difference:

#include <iostream>

class C {
public:
    C(int i) { }

    /*
    C operator<<(C const &rhs) {
        std::cout << "member non-const" << std::endl;
        return *this;
    }
    C operator<<(C const &rhs) const {
        std::cout << "member const" << std::endl;
        return *this;
    }
    //*/
};

C operator<<(C &lhs, C const &rhs) {
    std::cout << "non-member non-const" << std::endl;
    return lhs;
}
C operator<<(C const &lhs, C const &rhs) {
    std::cout << "non-member const" << std::endl;
    return lhs;
}

int main() {
    // Will print:
    // "non-member const" when member operators are commented out
    // "member non-const" when members are uncommented
    C(5) << 6;
}
Community
  • 1
  • 1
zennehoy
  • 6,405
  • 28
  • 55

1 Answers1

2

Rvalues cannot bind to references-to-nonconst, so only the reference-to-const overload of the free function is viable: operator<<(C(5), 6);.

This does not apply to the member-operator, which is simply C(5).operator<<(6), and the C-object isn't a function argument. You would have to say static_cast<const C &>(C(5)) << 6 to get the const version there, since it is the constness of this that distinguishes the two member operator overloads.

In the presence of both member and free-function operators, the member function is preferred, so putting all this together explains the observed behaviour.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Note that a special rule in the standard allows non-const member functions to be called on temporaries of the class type. In C++11, this can easily be disabled with a `&` ref-qualifier. – Xeo Jan 03 '12 at 13:24
  • Nice, quick answer, thanks! I'm so used to using non-member operators I forgot that member operators use this (i.e., not a reference) as their lhs. – zennehoy Jan 03 '12 at 13:28
  • @Xeo: Thanks - indeed, C++11 has ref-qualifiers for `this`, though I don't know of any compiler that implements them at this point. – Kerrek SB Jan 03 '12 at 14:57
  • 1
    @Kerrek: Clang 3.1 atleast does. :) Also, see [this answer of mine](http://stackoverflow.com/questions/8610571/what-is-rvalue-reference-for-this/8610728#8610728). There really are no "ref-qualifiers for `*this`, it's just a marketing statement that makes it way easier to understand. – Xeo Jan 03 '12 at 15:02