Рассмотрим следующий фрагмент кода:
int x = 1;
int y = 2;
y = x + (x = y);
Когда это выполняется в C #, переменным в конечном итоге присваиваются следующие значения:
х = 2
у = 3
С другой стороны, когда то же самое выполняется в C ++, переменные заканчиваются следующим образом:
х = 2
у = 4
Очевидно, компилятор C ++ использует разные старшинство, ассоциативность а также порядок оценки правила, чем C # (как объяснено в эта статья Эрика Липперта).
Итак, вопрос в следующем:
Можно ли переписать оператор присваивания, чтобы заставить C ++ оценить то же, что и в C #?
Единственное ограничение — хранить его как одну строчку. Я знаю, что это можно переписать, разбив назначения на две отдельные строки, но цель состоит в том, чтобы сохранить это в одной строке.
Да, это действительно возможно.
x = (y+=x) - x;
Так просто.
Можно ли переписать оператор присваивания, чтобы заставить C ++ оценить то же, что и в C #?
Да. Чтобы уточнить, правило в C # состоит в том, что большую часть времени левая сторона выражения полностью оценивается перед правой стороной. Таким образом, C # гарантирует, что оценка x
слева от +
происходит до того, как побочный эффект x = y
на правой стороне. C ++ не дает этой гарантии; составители могут не согласиться со значением этого выражения.
(Задача: я сказал «больше всего» по причине. Приведите пример простого выражения в C #, где побочный эффект слева выполняется после побочного эффекта справа.)
Я знаю, что это можно переписать, разбив назначения на две отдельные строки
Правильно. Вы хотите иметь утверждение, которое имеет два побочных эффекта: увеличить y на исходное значение x и присвоить исходное значение y x. Таким образом, вы могли бы написать это как
int t = y;
y = y + x;
x = t;
Но:
цель состоит в том, чтобы сохранить его в одной строке.
Я предполагаю, что под «линией» вы подразумеваете «утверждение». Хорошо. Просто используйте оператор запятой.
int t = ((t = y), (y = y + x), (x = t));
Очень просто. Почему вы хотите, я не знаю. Я предполагаю, что это головоломка, предназначенная для того, чтобы выявить, знаете ли вы об операторе запятой или нет.
Дополнительный кредит: Сколько скобок в этом утверждении требуется?
Супер бонус: что если мы не хотим использовать запятую? Мы можем использовать другие операторы в качестве операторов последовательности.
int t = ((t = y) & 0) || ((y = y + x) & 0) || (x = t);
Мы выполняем слева от ||
и оказывается ложным, поэтому мы выполняем правую часть и так далее.
Так же, ((expr1) & 0) ? 0 : (expr2)
гарантирует вам, что expr1
работает до expr2
,
В основном, здесь вам нужна гарантия того, что ряд подвыражений произойдет в определенном порядке. Найдите «точки последовательности», чтобы увидеть, какие операторы в C и C ++ создают точки последовательности; Вы можете использовать их для последовательности выражений, отсюда и название.
Вы могли бы написать:
int x = 1;
int y = 2;
y = std::exchange(x,y) + y;
Но крайне не рекомендуется. Вы даже должны прекратить просмотр и подумать об этой простой операции.