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.
精彩评论