Информация об изменениях

Сообщение Re[3]: КОгда выбирается move-constructor? от 15.07.2017 11:32

Изменено 15.07.2017 11:34 N. I.

Re[3]: КОгда выбирается move-constructor?
jazzer:

NI>>
void foo(TOnlyMovable&& object) {
NI>>    TOnlyMovable m(std::move(object));
NI>>}


J>А зачем здесь std::move? object ведь уже rvalue-ref


Тип переменной (в частности, параметра функции) может не совпадать с типом выражения, образованного этой переменной. В данном случае тип параметра object — TOnlyMovable&&, но тип выражения object — TOnlyMovable. Кстати, оба типа можно запросить через decltype: тип параметра будет эквивалентен decltype(object), а тип выражения — decltype((object)).

В контексте инициализации ссылки во внимание принимаются тип и value category выражения, а какой там declared тип у параметра, используемого в качестве выражения, имеет значение лишь в той мере, в которой это необходимо для определения типа выражения. Type & value category выражения object в данном случае определяются согласно C++14 [expr.prim.general] / 8

An identifier is an id-expression provided it has been suitably declared (Clause 7). [ Note: for operator-function-ids, see 13.5; for conversion-function-ids, see 12.3.2; for literal-operator-ids, see 13.5.8; for templateids, see 14.2. A class-name or decltype-specifier prefixed by ~ denotes a destructor; see 12.4. Within the definition of a non-static member function, an identifier that names a non-static member is transformed to a class member access expression (9.3.1). —end note ] The type of the expression is the type of the identifier. The result is the entity denoted by the identifier. The result is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise.


и C++14 [expr] / 5

If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.


Тип выражения может быть ссылочным только на первом этапе в процессе определения "настоящего" типа выражения, к которому затем применяются остальные правила. Выражение object — это lvalue типа TOnlyMovable. В отношении std::move(object) действуют правила для function call:

C++14 [expr.call] / 3:

If the postfix-expression designates a destructor (12.4), the type of the function call expression is void; otherwise, the type of the function call expression is the return type of the statically chosen function (i.e., ignoring the virtual keyword), even if the type of the function actually called is different. This return type shall be an object type, a reference type or cv void.

(ссылочность опять же удаляется в соответствии с C++14 [expr] / 5)

C++14 [expr.call] / 10:

A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.


Выражение std::move(object) — это xvalue типа TOnlyMovable.
Re[3]: КОгда выбирается move-constructor?
jazzer:

NI>>
void foo(TOnlyMovable&& object) {
NI>>    TOnlyMovable m(std::move(object));
NI>>}


J>А зачем здесь std::move? object ведь уже rvalue-ref


Тип переменной (в частности, параметра функции) может не совпадать с типом выражения, образованного этой переменной. В данном случае тип параметра object — TOnlyMovable&&, но тип выражения object — TOnlyMovable. Кстати, оба типа можно запросить через decltype: тип параметра будет эквивалентен decltype(object), а тип выражения — decltype((object)).

В контексте инициализации ссылки во внимание принимаются тип и value category выражения, а какой там declared тип у параметра, используемого в качестве выражения, имеет значение лишь в той мере, в которой это необходимо для определения типа выражения. Type & value category выражения object в данном случае определяются согласно C++14 [expr.prim.general] / 8

An identifier is an id-expression provided it has been suitably declared (Clause 7). [ Note: for operator-function-ids, see 13.5; for conversion-function-ids, see 12.3.2; for literal-operator-ids, see 13.5.8; for templateids, see 14.2. A class-name or decltype-specifier prefixed by ~ denotes a destructor; see 12.4. Within the definition of a non-static member function, an identifier that names a non-static member is transformed to a class member access expression (9.3.1). —end note ] The type of the expression is the type of the identifier. The result is the entity denoted by the identifier. The result is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise.


и C++14 [expr] / 5

If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.


Тип выражения может быть ссылочным только на первом этапе в процессе определения "настоящего" типа выражения, к которому затем применяются остальные правила. Выражение object — это lvalue типа TOnlyMovable. В отношении std::move(object) действуют правила для function call:

C++14 [expr.call] / 3:

If the postfix-expression designates a destructor (12.4), the type of the function call expression is void; otherwise, the type of the function call expression is the return type of the statically chosen function (i.e., ignoring the virtual keyword), even if the type of the function actually called is different. This return type shall be an object type, a reference type or cv void.

(ссылочность опять же удаляется в соответствии с C++14 [expr] / 5)

C++14 [expr.call] / 10:

A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.


Выражение std::move(object) — это xvalue типа TOnlyMovable.