#include <iostream>
struct Obj{ Obj(){} };
struct Obj2{ Obj2(){} };
// option 1
Obj operator+(Obj const& x0, Obj const& x1) { printf("%s\n", "+(const&, const&)"); return Obj{}; }
Obj operator+(Obj const& x0, Obj&& x1) { printf("%s\n", "+(const&, &&)"); return Obj{}; }
Obj operator+(Obj&& x0, Obj const& x1) { printf("%s\n", "+(&&, const&)"); return Obj{}; }
Obj operator+(Obj&& x0, Obj&& x1) { printf("%s\n", "+(&&, &&)"); return Obj{}; }
//option 2
// Obj2 operator+(auto const& x0, auto const& x1) { printf("%s\n", "+(const&, const&)"); return Obj2{}; }
// Obj2 operator+(auto const& x0, auto&& x1) { printf("%s\n", "+(const&, &&)"); return Obj2{}; }
// Obj2 operator+(auto&& x0, auto const& x1) { printf("%s\n", "+(&&, const&)"); return Obj2{}; }
// Obj2 operator+(auto&& x0, auto&& x1) { printf("%s\n", "+(&&, &&)"); return Obj2{}; }
int main()
{
Obj x0;
Obj x1{ x0 };
auto x2 = x0 + x1;
}
If I choose option 1, I get the expected call of (const&, const&) since x0 and x1 are clearly lvalues. BUT, if I go for option 2, it calls the (&&, &&) overload and thinks that x0 and x1 are rvalues?! Why is this happening? Serious question. Shouldn't it go for the more constrained version anyway and ignore option 2? Even so, should it even matter what option I go for when x0 and x1 should ALWAYS be lvalues?
BUT, if I go for option 2, it calls the (&&, &&) overload and thinks that x0 and x1 are rvalues?! Why is this happening?
This is because in option 2, the overloaded operators are actually "templated"(aka abbreviated function templates) and behave like you have template<typename T, typename U> operator+( T&&, U&&) etc which has forwarding references and among all the four overloads, the last overloaded version Obj2 operator+(auto&& x0, auto&& x1); is the best match for the call x0 + x1.
For example, Obj2 operator+(auto&& x0, auto&& x1) is basically the same as(or equivalent to writing)
template<typename T, typename U>
Obj2 operator+(T&& x0, U&& x1)
This means that what you have actually is:
template<typename T, typename U>
Obj2 operator+(T const& x0, U const& x1);
template<typename T, typename U>
Obj2 operator+( const& x0, auto&& x1);
template<typename T, typename U>
Obj2 operator+(T&& x0, U const& x1);
template<typename T, typename U>
Obj2 operator+(T&& x0, U&& x1); //this is best match for x0 + x1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With