xvalues: различия между не типами классов и типами классов

Рассмотрим минимальный пример ниже:

#include<utility>

struct S { };

int main() {
S s;
std::move(s) = S{};
}

Компилируется без ошибок.
Если вместо этого я использую не классовые типы, я получаю ошибку.
Например, приведенный ниже код не компилируется:

#include<utility>

int main() {
int i;
std::move(i) = 42;
}

То же самое происходит с перечислениями, перечислениями с областью видимости и так далее.
Ошибка (из GCC):

используя xvalue (ссылка на rvalue) в качестве lvalue

Что за этим стоит?

Я думаю, это правильно, но я хотел бы понять, по какой причине я могу сделать это со всеми типами, кроме неклассовых.

9

Решение

C ++ позволяет присваивать объекту rvalue объекта, но не примитиву rvalue;

Пример,

string s1, s2;
s1 + s2 = "asdf"; // ok since rvalue s1 + s2 is an object

int i1, i2;
i1 + i2 = 10;  // error, since i1 + i2 is a primitive type

То же правило относится к вашему вопросу. std :: move (s) возвращает r-значение типа объекта, но std :: move (i) возвращает r-значение примитивного типа.

4

Другие решения


Я пытаюсь ответить на свой вопрос с кучей ссылок на стандарт.
Я уверен, что напишу что-нибудь ужасно неправильно, и кто-то придет со мной, говоря словами.
Ну, я сделал все возможное, чтобы объяснить, как можно вывести из стандарта то, что описано в вопросе.
Не стесняйтесь понижать голос, если это необходимо, но, пожалуйста, дайте мне знать, что не так, чтобы иметь возможность исправить ответ и понять ошибку.
Спасибо.


3.9 / 8 (типы):

 тип объекта является (возможно, cv-квалифицированным) типом, который не является типом функции, не является ссылочным типом и не резюме недействительным.

5.2.2 / 10 (выражения, вызов функции):

Вызов функции является […] значением xvalue, если тип результата является ссылкой на тип объекта

таким образом std::move является xvalue выражение в обоих случаях.

5,18 / 3 (Назначение):

Если левый операнд не относится к типу класса, выражение неявно преобразуется […] в cv-неквалифицированный тип левого операнда.

Это не добавляет полезной информации, но это ради полноты.


4,1 / 2 (преобразование lvalue в rvalue):

В противном случае, если T имеет тип класса, преобразование копирует и инициализирует временное значение типа T из glvalue, и результат преобразования является предварительным значением для временного.

В противном случае значение, содержащееся в объекте, указанном в glvalue, является результатом prvalue.

12,2 (временные объекты) делает все остальное.

Итак, как упомянул @xaxxon в комментариях, я действительно пытался сделать (позвольте мне написать) 42 = 0; и это не является допустимым выражением в C ++.

Как правильно указано в комментариях @bogdan, правая часть стандарта, на которую следует ссылаться в этом случае, 5,18 / 1 (Назначение):

Все требуют изменяемого lvalue как их левый операнд […]

В то время как 5/2 а также 5/3 уточнить, что это утверждение относится только к встроенным операторам.

1

По вопросам рекламы [email protected]