std::move function and its argument

Hi,

I've been reading about r-value references and the fact that they can't bind to l-values.

But std::move function has the following definition:

1
2
template< class T >
typename std::remove_reference<T>::type&& move( T&& t );


And the code below is vaild:

1
2
string a; //l-value
move(a); //an "emtpy" instruction, but that's not the point 


So here's the question: why can we pass l-value to std::move function (look at its argument) since r-value reference can't take l-value ?
Last edited on
std::move isn't a function, it's a function template. First, it gets instantiated with T = string&, which makes its signature string&& move(string&) due to reference collapse rules. Only after instantiation, it will attempt to bind your argument (lvalue of type string) to the parameter (of type lvalue reference to string), which will, of course, succeed.

PS: for a simple demo, try to set T yourself: move<string>(a) and move<string&&>(a) will both fail to compile

Last edited on
due to reference collapse rules


Could you be more specific ?
When a reference to a reference is formed, they collapse:

T& & -> T& (lvalue ref to lvalue ref to T is lvalue ref to T)
T&& & -> T& (lvalue ref to rvalue ref to T is lvalue ref to T)
T& && -> T&
T&& && -> T&&

as first introduced in this proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm#s7

Last edited on
Simply said, the reference collaspe is that when a reference to areference is formed, it's a lvalue refrence if any of the references applied to the type is an lvalue reference, and an r-value reference otherwise.
Still don't get it, why:

First, it gets instantiated with T = string&


instead of just string ? Type of my variable a is string, not string&.
It's just a rule, to quote the standard:

If P is an rvalue reference to a cv-unqualified template parameter and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.

(where P is the function template parameter type and A is the type of the argument it's called with)

which was introduced specifically to handle this case (in the proposal I linked)
Last edited on

which was introduced specifically to handle this case (in the proposal I linked)


Oh, is the new C++ standard *that* bad? I think that the term "simplicity" is totally unknown to the creators of the language.
Last edited on
It's *that* good.
Excuse me, but how is that in any way bad? It adds simplicity, not removes it! Without that, the move() function would be much more complex, and there could be no perfect forwarding!
> Oh, is the new C++ standard *that* bad?

C++ (new or old) has always been strongly biased in favour of programmers who are willing to think for themselves.

Whether that is good or bad is a matter of opinion.

There are many other programming languages which do not exhibit such a strong bias; they could be more appropriate for a whole lot of programmers.


> I think that the term "simplicity" is totally unknown to the creators of the language.

No. Just that they realize that an overriding design goal of making easy things trivial, would result in making difficult things impossible. (IMHO of course).

Last edited on

There are many other programming languages which do not exhibit such a strong bias; they could be more appropriate for a whole lot of programmers.


C++ is strongly biased in favour of programmers who are willing to spend their time learning complex language rules, then learning even more complex exceptions to them (for handling special cases) and then exceptions to the exceptions (to patch problems with exceptions introduced with the prev standard), instead of spending their time on simply crunching the problem they have to solve.


No. Just that they realize that an overriding design goal of making easy things trivial, would result in making difficult things impossible. (IMHO of course).


C++ doesn't make possible any more things than other, simpler languages. Especially when we are talking about solving really hard to code problems.


Without that, the move() function would be much more complex, and there could be no perfect forwarding!


There is a dozen or more languages out there that support perfect forwarding, without need of such weird constructs like reference collapsing or inferring T& by default where T was given.
Last edited on
reference collapsing is a trivial and obvious property of any language with reified references. If the language doesn't have it, it is defective (as C++98 was, although the defect report was accepted long ago).

Using T& in deduction when lvalue argument comes across a T&& parameter (I don't understand your "T was given" part) is a logical extension of the same rule and it's very *good* because it fits forwarding right in without any need for additional complexity.
Topic archived. No new replies allowed.