Эквивалентность "a @= b" и "a = a @b"
Часто обсуждается (действительно, я думаю, что даже стандарт ссылается на него), что a @= b
и a = a @ b
эквивалентны. Здесь я использую @
для обозначения диапазона символов, таких как &
и ^
.
Однако я сомневаюсь, что они эквивалентны во время выполнения, особенно если a
является атомным типом. Например:
std::atomic_int a;
a ^= 1;
(который является атомным способом переключения a
), рассматривается как эквивалентный
a = a ^ 1;
Но этот второй способ состоит из не атома из-за назначения.
Поэтому я сомневаюсь в их буквальной эквивалентности, и компилятор (независимо от того, что говорит стандарт) не способен изменить более короткую форму на более длинную.
Правильно ли я?
Ответы
Ответ 1
Стандарт языка определяет только поведение встроенного
а не "пользовательские" перегрузки. И из
с точки зрения языка, нет встроенного оператора для
std::atomic_int
(который формально является "определяемым пользователем типом" );
std::atomic_int
является typedef для std::atomic<int>
, который
определяет количество перегрузок [email protected]=
, но не просто @
.
Итак, для
std::atomic_int i;
i ^= 1;
вторая строка будет:
i.operator^=( 1 );
но для:
std::atomic_int i;
i = i ^ 1;
вторая строка будет:
i.operator=( i.operator int() ^ 1 );
Можно утверждать, что это часть того, что подразумевается под "аргумент левой руки оценивается дважды, а не один раз".
В более общем плане, однако, определения для перегруженных
операторы - это то, что хотел автору оператора:
operator+=
может (насколько это касается языка)
фактически вычитают, даже когда operator+
добавлен. (У меня есть пара
случаев, когда operator+
действительно operator+=
. Это
обычно не хорошая идея, и в моем случае это происходит только с
классы, специально предназначенные для использования с std::accumulate
, и
задокументировано, чтобы использоваться только в этом случае.) Стандарт просто
не ограничивает определенные пользователем операторы
Ответ 2
Вы правы. На самом деле, они даже не гарантируются как эквивалентные в общем неатомном случае, так как класс может обеспечить разные перегрузки для +=
и +
, которые полностью независимы.
Ответ 3
Встроенные операторы имеют эту эквивалентность, за исключением того, что a @= b
оценивает только a
один раз, а a = a @ b
оценивает его дважды.
Однако это не встроенные операторы, а перегрузки, предоставляемые стандартной библиотекой. Они рассматриваются как отдельные, не связанные функции, поэтому компилятор не может изменить один на другой. (Фактически, как отмечено в комментариях, только операторы присваивания перегружены для атомных типов - вам придется явно загружать и сохранять значение для использования неатомной формы).
Ответ 4
Вы можете определить ^=
и ^
, чтобы сделать совершенно разные вещи. Таким образом, ни один компилятор не может изменить один на другой, только если он хочет