7

Why can't we implement both methods getAB() && and getAB(), but can implement any one of these?

  1. Works: http://ideone.com/4EgObJ

Code:

struct Beta {
  Beta_ab ab;
  Beta_ab && getAB() && { cout << "1"; return move(ab); }
};

int main() {    
    Beta_ab ab = Beta().getAB();

    return 0;
}

  1. Works: http://ideone.com/m9d0Tz

Code:

struct Beta {
  Beta_ab ab;
  Beta_ab && getAB() { cout << "2"; return move(ab); }
};

int main() {
    Beta b;
    Beta_ab ab = b.getAB();

    return 0;
}

  1. Doen't works: http://ideone.com/QIQtZ5

Code:

struct Beta {
  Beta_ab ab;
  Beta_ab && getAB() && { cout << "1"; return move(ab); }
  Beta_ab && getAB() { cout << "2"; return move(ab); }
};

int main() {
    Beta b;
    Beta_ab ab1 = b.getAB();

    Beta_ab ab2 = Beta().getAB();

    return 0;
}

Why are the first two examples of code works, but the last example does not work?

Barry
  • 247,587
  • 26
  • 487
  • 819
Alex
  • 11,148
  • 13
  • 83
  • 169
  • Unrelated to your problem, but when making an [MCVE](https://stackoverflow.com/help/mcve) make sure there are no unrelated errors in it. Unrelated errors distracts from the actual problem. I'm of course talking about your redefinition of the variable `ab` in the `main` function. – Some programmer dude Jun 10 '17 at 21:43
  • 4
    If any overload is reference-qualified then _all_ overloads must be reference-qualified – change the second overload to `Beta_ab && getAB() & { cout << "2"; return move(ab); }`. (Not posting as an answer because this is surely a dupe.) – ildjarn Jun 10 '17 at 21:48
  • 1
    An overload without ref qualifier, such as `Beta_ab && getAB()`, may be called on an lvalue *or* an rvalue. An overload with rvalue ref qualifier, `Beta_ab && getAB() &&`, may be called only on rvalues. Therefore, if both were allowed to coexist, the call of `getAB()` on an rvalue would be *ambiguous*. – Arne Vogel Jun 12 '17 at 09:40

1 Answers1

8

Standard section [over.load]/2.3:

Member function declarations with the same name and the same parameter-type-list as well as member function template declarations with the same name, the same parameter-type-list, and the same template parameter lists cannot be overloaded if any of them, but not all, have a ref-qualifier.

[Example:

class Y {
  void h() &;
  void h() const &;    // OK
  void h() &&;         // OK, all declarations have a ref-qualifier
  void i() &;
  void i() const;      // ill-formed, prior declaration of i
                       // has a ref-qualifier
};

-- end example ]

It's not entirely clear to me exactly why we have this rule, but that's what it is. (Though I guess the alternative of trying to work something into the overload resolution rules would take some work, at least.)

The solution is obvious: add an lvalue (&) ref-qualifier to your "2" overload so that one only takes rvalues and one only takes lvalues.

Barry
  • 247,587
  • 26
  • 487
  • 819
aschepler
  • 65,919
  • 8
  • 93
  • 144