Должен ли я использовать ссылочные квалификаторы lvalue для операторов присваивания?

Недавно я следил за обсуждением присвоений выражений в C ++, как показано в следующем примере:

string s1, s2, s3;
(s1 + s2) = s3;

В C ++ 11 можно ограничить оператор присваивания ссылками lvalue (слева). При объявлении операторов присваивания следующим образом компилятор Clang отклоняет код с сообщением об ошибке из-за несовместимых типов.

auto operator=(const string& rhs) & -> string&;
auto operator=(string&& rhs) & -> string&;

Я не видел это нигде. Есть ли веская причина не использовать ссылочные квалификаторы lvalue для операторов присваивания (помимо отсутствия поддержки в большинстве компиляторов)?

12

Решение

Нет, не совсем. Использование квалификаторов lvalue или rvalue для создания правильного интерфейса для объектов lvalue или rvalue — это то же самое, что и использование constи к нему следует подходить одинаково — каждая функция должна рассматриваться на предмет ограничения. Присвоение rvalue на самом деле не имеет смысла, поэтому оно должно быть запрещено.

Причина, по которой вы не видели, это в основном плохая поддержка компилятора. *this это вроде как thread_localбольшинство разработчиков компиляторов, похоже, поместили его в конец стека «Особенности реализации из C ++ 11».

4

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

Интересно! Я даже не знал об этом, и мне потребовалось время, чтобы найти его (это было частью «Расширение семантики перемещения на * this» предложение). Обозначение определено в параграфе 4 8.3.5 [dcl.decl] на случай, если кто-нибудь захочет посмотреть.

В любом случае: теперь, зная об этой функции, кажется, что наиболее полезно использовать ее для перегрузки и, возможно, вести себя по-разному, если объект, для которого вызывается функция, является lvalue или rvalue. Использование его для ограничения того, что может быть сделано, например, с помощью результата присваивания, кажется ненужным, особенно если объект фактически является lvalue. Например, вы можете захотеть, чтобы синтаксис возвращал значение r от присвоения значения rvalue:

struct T {
auto operator=(T&) & -> T&;
auto operator=(T&&) & -> T&;
auto operator=(T&) && -> T;
auto operator=(T&&) && -> T;
};

Намерение здесь будет состоять в том, чтобы разрешить переход от результата назначения (стоит ли оно того, хотя я не уверен: почему бы не пропустить назначение в первую очередь?). Я не думаю, что я бы использовал эту функцию в первую очередь для ограничения использования.

Лично мне нравится возможность иногда получить lvalue от rvalue, и оператор присваивания часто является способом сделать это. Например, если вам нужно передать lvalue в функцию, но вы знаете, что не хотите ничего с ней использовать, вы можете использовать оператор присваивания, чтобы получить lvalue:

#include <vector>
void f(std::vector<int>&);
int main()
{
f(std::vector<int>() = std::vector<int>(10));
}

Это может быть злоупотребление оператором присваивания для получения lvalue из rvalue, но это вряд ли произойдет случайно. Таким образом, я не стал бы изо всех сил делать это невозможным, ограничивая использование оператора присваивания только для l-значений. Конечно, возврат rvalue из присваивания в rvalue также предотвратит это. Какое из двух использований более полезно, если таковые имеются, может быть вопрос.

Кстати, Clang, кажется, поддерживает синтаксис, который вы цитировали начиная с версии 2.9.

8

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

Конечно, для тех случаев, когда я пишу класс или шаблон класса, например, управлять владением (см. заключение в приведенной выше ссылке), я мог бы позаботиться о том, чтобы объявить эти операторы только для lvalues. Однако, поскольку это не влияет на клиентов, в этом нет особого смысла.

3
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector