8

Why is this rvalue call ambiguous? I can have AA and AA& and the compiler will know to use AA&. But when i add in the third option i get an error. Obviously AA&& is a better overload then the others like int for an int is better then long. Why is this ambiguous? Is there a way i can keep all 3 overloads and make it clear which one i want? (Typecasting (AA&&) will not do it).

struct AA{
    void*this_;
    AA() { this_=this; }
    //not valid, use AA&, AA(AA a){ this_=this; }
    AA(AA&a){ this_=this; }
    AA(AA&&a){ this_=a.this_; }
};
void movetest(AA s) {}
void movetest(AA& s) {}
//This gets me the ambiguous error void movetest(AA&& s) {}
AA&& movetest() { return AA(); }
void MyTestCode2(){
    AA a;
    AA b(a);
    AA c = movetest();
    movetest(AA());
}
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 2
    (On a side note, your zero-arity `movetest` function returns a reference to a local variable.) – GManNickG Apr 08 '11 at 05:38
  • (I'll also say normally you wouldn't want all three overloads anyway.) – GManNickG Apr 08 '11 at 05:43
  • @GMan: What... why? huh? Maybe you can explain this as well http://stackoverflow.com/questions/5591995/is-move-by-lvalue-broken-unfinished-in-msvc2010 –  Apr 08 '11 at 07:41

2 Answers2

8

I can have AA and AA& and the compiler will know to use AA&

Yes, in the case of movetest(AA());, only movetest(AA) is viable, because a (lvalue) reference to non-const cannot be bound to an rvalue. However, an rvalue reference is said to bind directly to a temporary. Thus, for overload resolution purposes the functions

void movetest(AA)
void movetest(AA&&)

are equal, because the implicit conversion sequences used to convert AA() to AA and AA&&, respectively, are equal. The former is not better, because the direct reference binding is also considered an identity conversion.

decltype
  • 1,591
  • 8
  • 12
  • Is the rule basically if you have a function that takes a parameter by value you shouldn't have any other overloads? – Clinton Apr 09 '11 at 07:19
2

Agreed with decltype. This is really no different than this C++03/98 ambiguity:

struct AA {};

void movetest(AA s) {}
void movetest(AA& s) {}

int main()
{
    AA a;
    movetest(a);
}

test.cpp:9:5: error: call to 'movetest' is ambiguous
    movetest(a);
    ^~~~~~~~
test.cpp:3:6: note: candidate function
void movetest(AA s) {}
     ^
test.cpp:4:6: note: candidate function
void movetest(AA& s) {}
     ^
1 error generated.
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577