Эквивалентность "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

Вы можете определить ^= и ^, чтобы сделать совершенно разные вещи. Таким образом, ни один компилятор не может изменить один на другой, только если он хочет