Comment by HarHarVeryFunny

13 hours ago

I'm not sure what you are saying.

If we have foo(std::string a, std string b), and then call it like this:

std::string x;

std::string y;

foo(std::move(x), y);

Then x will be moved into a, and y will be copied into b.

The callee has no say in this - it's just the compiler implementing the semantics of the language.

Who says there's only one resolution candidate? A different overload could be defined elsewhere that the compiler prefers for that particular combination of arguments, that doesn't cause a copy. std::move() works the same way. The semantics of the operation is defined not by what's at the call site, but by the context.

  • Sure overload resolution happens first, but once the compiler has found the correct match then the way arguments are passed depends only on the function signature of that match (callee), and how the caller is passing.

    An argument passed to a value parameter will be passed by copying, unless it's an rvalue (e.g. forced with std:move) where a move constructor has been defined for that type, in which case it will be moved. The callee has no say in this.

    • >Sure overload resolution happens first, but once the compiler has found the correct match then the way arguments are passed depends only on the function signature of that match (callee), and how the caller is passing.

      Yes, and std::move() works exactly the same. The compiler first determines whether to move or to copy, and then generates the call to the corresponding constructor or assignment operator. Just like how foo(x) doesn't tell you anything about whether a value is being copied, foo(std::move(x)) doesn't tell you anything about whether a value is being moved.

      You might say "well, you need to look at all the signatures of foo() to tell if there's a copy", and to that I say, "yeah, and you need to look at what x is to tell if there's a move".

      4 replies →