开发者

Why is f(x).swap(v) okay but v.swap(f(x)) is not?

开发者 https://www.devze.com 2023-01-23 20:32 出处:网络
We have: vector<int> f(int); vector<开发者_Python百科int> v; This works: f(x).swap(v); This doesn\'t:

We have:

vector<int> f(int);

vector<开发者_Python百科int> v;

This works:

f(x).swap(v);

This doesn't:

v.swap(f(x));

And why?


swap() takes a non-const reference to a vector<int>. A non-const reference cannot bind to an rvalue (a temporary object). A call to a function that returns by value (like f) is an rvalue.

The reason that f(x).swap(v) works is because inside of std::vector<int>::swap, the temporary object returned by f(x) can use this to refer to itself. this is not an rvalue.


You are allowed to call member functions on temporaries but in C++ they cannot be bound to non-const references.

For example:

int &x = 5; // illegal because temporary int(5) cannot be bound to non-const reference x


Actually, (while James' answer is certainly right (and so is Prasoon's), there is some underlying problem to grasp.

When we reduce f(x) to its result y, and y.swap(v) (or v.swap(y), it doesn't matter in this case) to use generalized identifier names, it becomes

y.func(v)

Now, func() being a member function with one argument, it actually has two arguments: what's been passed in as v, and the implicit this pointer every non-static member function receives, here bound to y. Tossing encapsulation aside, every member function called as y.func(v) could be made a non-member function to be called as func(y,v). (And in fact, there actually are a non-member swap() functions. Also, each time you need to overload one of those binary operators that could be overloaded both as members or non-members, you have to make this decision.)

However, there are subtle differences between y.func(v) and func(y,v), because C++ treats the this argument, the argument that's passed by writing it before the . (the dot), different than the other arguments, and it does so in many ways.
As you have discovered, the this argument might be an rvalue (temporary) even for non-const member functions, while for the other arguments, a non-const reference prevents rvalues from being bound to the argument. Also, the this argument's run-time type might influence which function is called (for virtual members), while the other arguments' run-time type is irrelevant, because a function is chosen only depending on their compile-time type only. And implicit conversions are only ever applied to the explicit arguments of a member functions, but never to its implicit this argument. (That's why you can pass a string literal for a const std::string&, but cannot call std::string::size() on a string literal.)

So, to conclude, despite the fact that what's before the . ends up as an (implicit) function argument, it's actually treated very differently from the other function arguments.

0

精彩评论

暂无评论...
验证码 换一张
取 消