Подтвердить что ты не робот

Какие выражения создают значения xvalues?

Я пытаюсь понять концепции С++ 11.

Стандартный проект, который я сказал:

Значение x (значение "eXpiring" ) также относится к объекту, обычно ближе к концу его жизни (так что его     ресурсы могут быть перемещены, например). Значение x является результатом определенных видов выражений, связанных с     rvalue-ссылки (8.3.2). [Пример: результат вызова функции, тип возврата которой является значением rvalue     reference - значение x. -end пример]

ОК, так что же такое "определенные типы выражений", которые производят значения xvalues? Эта часть спецификации не детализирует список этих выражений.

Я понимаю lvalue и prvalue (по крайней мере, я думаю, я понимаю).

4b9b3361

Ответ 1

Существует полезная ненормативная нота во введении к §5 (С++ 11 §5 [expr]/6):

[Примечание: выражение представляет собой значение x, если оно:

  • результат вызова функции, неявно или явно, чей тип возврата является ссылкой rvalue на тип объекта,

  • приведение к ссылке rvalue на тип объекта,

  • выражение доступа к члену класса, обозначающее нестатический элемент данных не ссылочного типа, в котором выражение объекта является значением x, или

  • a .* выражение "указатель-к-член", в котором первым операндом является значение x, а второй операнд является указателем на элемент данных.

В общем, эффект этого правила заключается в том, что именованные ссылки rvalue рассматриваются как lvalues, а неназванные ссылки rvalue на объекты рассматриваются как xvalues; Ссылки rvalue на функции обрабатываются как lvalues, имена или нет. -end note]

Поиск по остальной части § 5, этот список выглядит исчерпывающим. За ним следует пример:

struct A {
    int m;
};

A&& operator+(A, A);
A&& f();
A a;
A&& ar = static_cast<A&&>(a);

Выражения f(), f().m, static_cast<A&&>(a) и a + a являются значениями x. Выражение ar является значением l.

Существует два распространенных способа получения выражения xvalue:

  • Используйте std::move для перемещения объекта. std::move выполняет static_cast для ссылочного типа rvalue и возвращает ссылку rvalue.

  • Используйте std::forward для перенаправления значения r. std::forward обычно используется в шаблоне функции, чтобы обеспечить идеальную пересылку аргумента функции.

    Если аргумент, предоставленный шаблону функции, был rvalue, тип параметра будет ссылкой rvalue, которая является значением lvalue. В этом случае std::forward выполняет static_cast для ссылочного типа rvalue и возвращает ссылку rvalue.

    (Примечание. Если аргумент, предоставленный шаблону функции, был lvalue, тип параметра будет ссылкой lvalue, а std::forward вернет ссылку lvalue.)

Ответ 2

Пункт 5, в котором описывается синтаксис допустимых выражений, списки для каждого синтаксиса выражения условия, в которых выражение является значением l, значением x или значением prvalue. Полный список возможных значений x из пункта 5:

5.2.2 параграф 10: вызов функции - это... значение xvalue, если тип результата является ссылкой rvalue на тип объекта.

(На техническом языке стандарта "тип объекта" не означает "тип класса". "Тип объекта" включает в себя основные типы, указатели и массивы и исключает только типы функций. Ссылка на rvalue для типа функции всегда обрабатывается как lvalue, а не xvalue.)

Наиболее заметными функциями, возвращающими ссылку rvalue, являются, конечно, std::move, а иногда std::forward.

5.2.5, пункт 4: Если E2 является нестатическим членом данных... если E1 является значением x, то E1.E2 является значением xvalue

(С другой стороны, поиск элемента данных E1->E2 всегда является lvalue.)

Аналогично, если E1 является значением x, то поиск элемента данных E1.*E2 представляет собой значение x:

5.5. Пункт 6: Результат выражения .*, второй операнд которого является указателем на элемент данных, имеет одну и ту же категорию значений (3.10) в качестве своего первого операнда.

Для различных типов приводов:

  • dynamic_cast<Type>(expr): 5.2.7 пункт 2
  • static_cast<Type>(expr): 5.2.9 пункт 1
  • reinterpret_cast<Type>(expr): 5.2.10 пункт 1
  • const_cast<Type>(expr): 5.2.11 пункт 1
  • (Type) expr: 5.4 пункт 1

выражение является значением xvalue тогда и только тогда, когда Type является ссылкой rvalue на тип объекта. То же самое верно и для Type(expr), так как

5.2.3, пункт 1: Если список выражений [в круглых скобках, следующих за именем типа], является одним выражением, выражение преобразования типа эквивалентно (в определении и, если определено по смыслу), соответствующему выражению (5.4).

(С другой стороны, Type{expr} всегда является prvalue.)

Раздел 5.16 об условном операторе заканчивается тем, что A ? B : C может иногда быть значением x, если B и/или C является значением x. Но полные правила трудно подвести.

Если выражение заканчивается вызовом пользовательской перегруженной операторной функции, то раздел 5.2.2 применяется к этому выражению, а не к тому, которое описывает встроенное поведение оператора. (См. Выражение a + a в приведенном примере @James.)

Ответ 3

Что я понимаю из того, что я прочитал, так это то, что вызов чего-то значения xvalue - это причудливый способ сказать:

Значение x - это просто rvalue, чье хранилище может быть освобождено, поэтому его использование означает, что вы должны сами проверить его существование.

Как правило, это один или несколько уровней косвенности от фактического значения r.

В отличие от этого, у rvalue гарантируется наличие существующего пространства для хранения до тех пор, пока оно находится в области видимости.

Возможно, я ошибаюсь, но это то, что я понял.