📜 ⬆️ ⬇️

Do you understand move semantics?

Good day!

Just yesterday, I honestly thought that I figured out how rvalue references work in C ++ 11. I thought until I came across a rake.

So, I propose to stretch your brains and try to write the function move_if_rr. Such an understanding test: success is counted for a function that works correctly, provided that you have never debugged it. Job details under the cut.
')
So the condition.
Suppose there is the following code:
template < class U >
class Container
{
U member ;

public :

U & Get ( ) { return member ; }
const u & get ( ) const { return member ; }

public :

template < class T > void dummy ( const Container < T > & ) ; // copy
template < class T > void dummy ( Container < T > && ) ; // move

public :

// T is expected to be something compatible with Container
template < class T >
void Fwd ( T && rr )
{
member = move_if_rr < T > ( rr. Get ( ) ) ;
// dummy (std :: forward <T> (rr))
}
} ;
Container is intentionally made a template so that the real member type is unknown.
The dummy functions are only needed to clarify the move_if_rr semantics (below).
The above code does not carry any meaning, all matches are considered random.

You must write the function move_if_rr , which satisfies the following rules:
If commented forward in Container.Fwd , will call dummy , marked as move:
* Using move_if_rr should result in a call to the move-assignment of the member field.
If commented forward in Container.Fwd , will call dummy marked as copy:
* Using move_if_rr should result in a call to the copy-assignment of the member field.
Both rules assume that the Container type was passed as an argument to Container.Fwd .

Decisions are awaited in the comments.

UPD1. To lay out the code, you can use highlight.hohli.com (you need to tick the "Use font tag (for Habrahabr)")

UPD2. For those who do not understand what move_if_rr is:
This is an extended version of std :: forward: Using std :: forward you cannot specify one type as a template argument, and another type as a parameter, move_if_rr solves this particular problem. What for?
because if I was given a type by an rvalue link, then all its internal components can also be considered as passed by an rvalue link. Only here is how to explain this to the compiler, if I didn’t explicitly indicate how I was given this very certain type, but used standard forward-notation?
Example:
Suppose there was such a function:
template < class T >
void f ( T && rr )
{
SendData ( std :: forward < T > ( rr ) ) ;
}
And then something changed in the program, and the composite type began to come into it (the old type in it is like a field). How to transfer this field with a forvarding, as before? C move_if_rr it looks like this:
template < class T >
void f ( T && rr )
{
SendData ( std :: move_if_rr < T > ( rr. GetSomeElement ( ) ) ) ;
}

UPD 3. The condition is slightly rephrased, because The previous formulation allowed to cling to the semantics of constructors (instead of Fwd, a constructor was used).

UPD 4. You can check the solution by inserting it at the beginning of this code , you can find the fully correct version here , there is also an option from SergX - without using mpl

Source: https://habr.com/ru/post/140578/


All Articles