如何使 C++ 编译器遵循与 C# 在 this 赋值语句中相同的优先级、关联性和求值顺序?
How to make the C++ compiler to follow the same precedence, associativity and order of evaluation that C# has in the this assignment statement?
考虑以下代码:
int x = 1;
int y = 2;
y = x + (x = y);
当它在 C# 中运行时,变量最终分配有这些值:
x = 2
y = 3
另一方面,当在 C++ 中运行时,变量的结尾是这样的:
x = 2
y = 4
显然,C++ 编译器使用不同的优先级、关联性和计算顺序比 C# 规则(如 this Eric Lippert's article 中所述)。
所以,问题是:
是否可以重写赋值语句以强制 C++ 求值与 C# 相同?
唯一的限制是将其保持为单行。我知道这可以通过将作业分成两行来重写,但目标是将它保持在一行中。
你可以这样写:
int x = 1;
int y = 2;
y = std::exchange(x,y) + y;
但非常不推荐。你甚至不得不停止浏览并思考这个简单的操作。
是的,确实有可能。
x = (y+=x) - x;
就这么简单。
Is it possible to rewrite the assignment statement to force C++ to evaluate the same as C# does?
是的。需要澄清的是,C# 中的规则是,大多数时候,表达式的左侧先于右侧进行完整计算。因此 C# 保证 +
左侧的 x
的计算发生在右侧 x = y
的副作用之前。 C++ 不作此保证;编译器可能不同意此表达式的含义。
(挑战:我说 "most" 是有原因的。举一个 C# 中的简单表达式示例,其中左侧的副作用在右侧的副作用之后执行。)
I know this can be rewritten by splitting the assignments into two separate lines
没错。您希望有一个具有两个副作用的语句:将 y 增加 x 的原始值,并将 y 的原始值赋给 x。所以你可以把它写成
int t = y;
y = y + x;
x = t;
但是:
the goal is to maintain it in a single line.
我假设 "line" 你的意思是 "statement"。美好的。只需使用逗号运算符即可。
int t = ((t = y), (y = y + x), (x = t));
简单易行。为什么你会想要,我不知道。我假设这是一个谜题,旨在引出您是否知道逗号运算符的信号。
加分项:该语句中需要多少括号?
超级奖励:如果我们不想使用逗号运算符怎么办?我们可以使用其他算子作为排序算子。
int t = ((t = y) & 0) || ((y = y + x) & 0) || (x = t);
我们执行||
的左边,结果是false,所以我们执行右边,以此类推。
同样,((expr1) & 0) ? 0 : (expr2)
保证 expr1
在 expr2
之前运行。
基本上,您在这里需要的是保证多个子表达式以特定顺序出现。查找 "sequence points" 以查看 C 和 C++ 中的哪些运算符产生序列点;您可以使用它们对表达式进行排序,因此得名。
考虑以下代码:
int x = 1;
int y = 2;
y = x + (x = y);
当它在 C# 中运行时,变量最终分配有这些值:
x = 2
y = 3
另一方面,当在 C++ 中运行时,变量的结尾是这样的:
x = 2
y = 4
显然,C++ 编译器使用不同的优先级、关联性和计算顺序比 C# 规则(如 this Eric Lippert's article 中所述)。
所以,问题是:
是否可以重写赋值语句以强制 C++ 求值与 C# 相同?
唯一的限制是将其保持为单行。我知道这可以通过将作业分成两行来重写,但目标是将它保持在一行中。
你可以这样写:
int x = 1;
int y = 2;
y = std::exchange(x,y) + y;
但非常不推荐。你甚至不得不停止浏览并思考这个简单的操作。
是的,确实有可能。
x = (y+=x) - x;
就这么简单。
Is it possible to rewrite the assignment statement to force C++ to evaluate the same as C# does?
是的。需要澄清的是,C# 中的规则是,大多数时候,表达式的左侧先于右侧进行完整计算。因此 C# 保证 +
左侧的 x
的计算发生在右侧 x = y
的副作用之前。 C++ 不作此保证;编译器可能不同意此表达式的含义。
(挑战:我说 "most" 是有原因的。举一个 C# 中的简单表达式示例,其中左侧的副作用在右侧的副作用之后执行。)
I know this can be rewritten by splitting the assignments into two separate lines
没错。您希望有一个具有两个副作用的语句:将 y 增加 x 的原始值,并将 y 的原始值赋给 x。所以你可以把它写成
int t = y;
y = y + x;
x = t;
但是:
the goal is to maintain it in a single line.
我假设 "line" 你的意思是 "statement"。美好的。只需使用逗号运算符即可。
int t = ((t = y), (y = y + x), (x = t));
简单易行。为什么你会想要,我不知道。我假设这是一个谜题,旨在引出您是否知道逗号运算符的信号。
加分项:该语句中需要多少括号?
超级奖励:如果我们不想使用逗号运算符怎么办?我们可以使用其他算子作为排序算子。
int t = ((t = y) & 0) || ((y = y + x) & 0) || (x = t);
我们执行||
的左边,结果是false,所以我们执行右边,以此类推。
同样,((expr1) & 0) ? 0 : (expr2)
保证 expr1
在 expr2
之前运行。
基本上,您在这里需要的是保证多个子表达式以特定顺序出现。查找 "sequence points" 以查看 C 和 C++ 中的哪些运算符产生序列点;您可以使用它们对表达式进行排序,因此得名。