В C++ генерируется значения (rvalue?) встроенных типов не могут быть присвоены:
Код: Выделить всё
int generator_double() {
return 50;
}
...
generator_double() = 60; // error: expression is not assignable
Однако наивно разработанные пользовательские классы не подчиняются этому правилу.
Код: Выделить всё
struct UserClass {
int val_;
};
UserClass generator_user_class() {
return UserClass{99};
}
...
generator_user_class1() = UserClass{66}; // compiles
Я думаю, это разрешено, потому что оператор= может иметь побочный эффект, который не будет отброшен.< /p>
Или, возможно, кто-то захочет передать это присвоенное значение третьей функции fun(generator_user_class1() = UserClass{66});, хотя для чистого значения это должно быть то же, что fun(UserClass{66});.
Итак, это вдохновляет как минимум на 3 или 4 различных способа реализации присваивания и постепенного улучшения возможно противоречивой исходной версии:
- Это поведение по умолчанию:
Код: Выделить всё
struct UserClass1 {
int val_;
UserClass1& operator=(UserClass1 const& other) & = default;
UserClass1& operator=(UserClass1 const& other) && = default;
};
UserClass1 generator_user_class1() { return UserClass1{99}; }
...
generator_user_class1() = UserClass1{66}; // compiles, can be misleading
- отключить назначения по r-значениям
Код: Выделить всё
struct UserClass2 {
int val_;
UserClass2& operator=(UserClass2 const& other) & = default;
UserClass2&& operator=(UserClass2 const& other) && = delete;
};
UserClass2 generator_user_class2() { return UserClass2{99}; }
...
generator_user_class1() = UserClass1{66};
- разрешить присваивание значения r, например 1), но пометить возврат как не отбрасываемый.
Код: Выделить всё
struct UserClass3 {
int val_;
UserClass3& operator=(UserClass3 const& other) & = default;
[[nodiscard]] UserClass3&& operator=(UserClass3 const& other) && {
return std::move(operator=(other));
}
};
UserClass3 generator_user_class3() { return UserClass3{99}; }
...
generator_user_class3() = UserClass3{66}; // warns because of [[nodiscard]]
- четвертый вариант, который было бы неплохо заставить его работать, — это объявить весь класс как [[nodiscard]] и заставить все это работать автоматически, но это не помогло, а просто заставило меня реализовать оператор = && для возврата по значению.
Итак, Каков правильный современный способ реализации присваивания?
Существуют ли в настоящее время другие идиомы для справиться с этим?
(Для простоты обсуждение можно ограничить типами, которые являются семантически значениями.)
Подробнее здесь: https://stackoverflow.com/questions/786 ... alue-types