3
#include <iostream>

struct A
{
    void f() const &
    {
        std::cout << "A::f()&" << std::endl;
    }

    void f() const &&
    {
        std::cout << "A::f()&&" << std::endl;
    }
};

struct B
{
    void f() const &
    {
        std::cout << "B::f()&" << std::endl;
    }
};

int main()
{
    A{}.f();
    B{}.f();
}

The output is:

A::f()&&

B::f()&

Note that void B::f() const && doesn't exist.

To me, a temporary object of B calls B::f, void B::f() const && should be chosen, or a compiler error should be raised.

Why is void B::f() const & chosen in such a case?

xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • 1
    I think it is just because you simply don't have a `void f() const &&`, C++ seem to tend to allow you writing more flexible code than confining you to do micro optimizations manually. This is similar to using the `Object(const Object &)` if calling it with `std::move(object)` if there is no move constructor. – user9335240 Oct 26 '18 at 01:38

1 Answers1

5

Because void B::f() const && doesn't exist, the next best candidate is selected which is your void B::f() const &. The rvalue will bind to a const &. If you remove the const you will notice you will get a compile error as the rvalue cannot bind to a non-const reference. The example on cppreference/overloadresolution shows it perfectly.

int i;
int f1();
int g(const int&);  // overload #1
int g(const int&&); // overload #2
int j = g(i);    // lvalue int -> const int& is the only valid conversion
int k = g(f1()); // rvalue int -> const int&& better than rvalue int -> const int&

This is no different for the implicit this argument in your examples.

To me, a temporary object of B calls B::f, void B::f() const && should be chosen, or a compiler error should be raised.

if this was the case then code like the following would break without a [const] rvalue reference overload existing.

void f(const int& i)
{
    std::cout << i;
}

int main()
{
    f(3);
}
rmawatson
  • 1,909
  • 12
  • 20