C++ 三元运算符的第二个或第三个参数为空或不执行任何操作
三元运算符是否可以有一个空白的第二个或第三个参数,或者有一个非上下文特定且表示“不做任何事情”的参数?在下面的例子中,我想让一个三元运算符将一个整数变量乘以2,如果它是偶数,或者什么都不做。对于第三个参数,除了自赋值、加或减零、乘或除一之外,我想不出任何东西。无论如何,它们都是特定于上下文的。我想要对所有三元运算符都表示“不做任何事情”。我试着把参数留空,但它无法编译C++ 三元运算符的第二个或第三个参数为空或不执行任何操作,c++,c++11,ternary-operator,conditional-operator,C++,C++11,Ternary Operator,Conditional Operator,三元运算符是否可以有一个空白的第二个或第三个参数,或者有一个非上下文特定且表示“不做任何事情”的参数?在下面的例子中,我想让一个三元运算符将一个整数变量乘以2,如果它是偶数,或者什么都不做。对于第三个参数,除了自赋值、加或减零、乘或除一之外,我想不出任何东西。无论如何,它们都是特定于上下文的。我想要对所有三元运算符都表示“不做任何事情”。我试着把参数留空,但它无法编译 #include <iostream> int main() { int x = 5; (x %
#include <iostream>
int main()
{
int x = 5;
(x % 2 == 0) ? x *= 2 : x = x; // or x += 0, x -= 0, x *= 1, or x /= 1
std::cout << x << std::endl;
return 0;
}
当前,(x%2==0)?x*=2:x=x
并不比if语句好:
if (x % 2 == 0) x *= 2; // This is okay for one-liners.
如果要保留三元运算符,无需写入x=x
,可以将整行设置为赋值语句,并使用三元运算符选择值:
x = (x % 2 == 0)? x * 2 : x;
不过我还是坚持if的说法。这似乎更清楚。您无法跳过三元运算符的参数。 如果函数需要调用一次,那么您可以这样使用。 如果foo()和goo()的返回值都是布尔值,则可以使用简单或运算符来获得最终结果
bool ResultOfFoo = foo();
bool ResultOfGoo = goo();
bool RequiredResult = ResultOfFoo ? ResultOfGoo : ResultOfFoo ;
优化
bool RequiredResult = ResultOfFoo || ResultOfGoo;
条件运算符不是一个if语句,它的作用是生成一个值,如果您不需要该值,如上所述,只需按原样键入if
:
if (x%2==0) x*=2;
它更易于阅读和维护,在所有其他方面都是等效的。如果您认为您的代码在任何方面都会更好,请重新考虑它
从问题中的一条评论来看,您似乎想了解它是如何工作的,而不仅仅是编写外观怪异的代码。如果是这样的话,运算符是非常有趣的,但有趣的位不是您是否可以将它与3或2个运算符一起使用。相反,运算符最有趣的行为是当第二个和第三个参数的类型不相同时,它会产生什么(同样,它的目的是产生一个值)
与所有其他生成值的表达式一样,无论条件的值是什么,三元运算符的类型都是固定的,因此编译器必须确定整个表达式的类型,并且必须是与两个参数兼容的类型。这些规则很有趣,也太复杂,无法在这里解释,但你应该看看
另外,虽然它不适合您的问题,这也是我没有在前面介绍它的原因,但不是两个分支都需要生成值,它们中的一个或两个可以是
throw
表达式,在这种情况下,类型是另一个参数的类型。此外,如果两者都是throw
表达式或类型为void
的表达式,则三元运算符的类型为void
本身。如果要使用三元运算符,可能需要指定其结果:
x = (x % 2 == 0) ? 2 * x : x;
就我个人而言,我想我应该用一点数学知识:
x <<= ((x & 1) ^ 1);
[注意:对于此源代码,g++生成几乎相同的目标代码]
忽略从内存加载x
的(可能)时间,这应该在大约386的任何英特尔处理器上以不超过4个时钟周期执行。更妙的是,我希望任何处理器的编译器都能产生类似的结果——几乎任何合理处理器的源代码到汇编语言的直接直译将在四条指令中完成实际的数学运算,每一条指令都尽可能简单和快速
使用if
语句的版本如下所示:
; Line 2
mov ecx, DWORD PTR _x$[esp-4]
mov eax, ecx
and eax, -2147483647 ; 80000001H
jns SHORT $LN5@f
dec eax
or eax, -2 ; fffffffeH
inc eax
$LN5@f:
lea eax, DWORD PTR [ecx+ecx]
je SHORT $LN1@f
; Line 3
mov eax, ecx
$LN1@f:
就编译而言,这并不太糟糕。它至少避免了div
,这是实现%2
的明显方式。不幸的是,它仍然不够聪明,不足以具有竞争力——它仍然有几个分支,其中一个分支可能不太可预测,因此大约有一半的时间我们会为预测失误的分支付出代价
根据编译器的不同,您可以(也将)看到更好的结果。例如,使用g++替代,我得到以下结果:
mov eax, DWORD PTR [ebp+8]
and eax, 1
test eax, eax
jne L2
sal DWORD PTR [ebp+8]
L2:
mov eax, DWORD PTR [ebp+8]
虽然在这段代码上肯定比VC++做得更好,但仍然远不及数学版本。特别是,除非最低有效位是相当可预测的偶数或奇数,否则该分支很可能在大约一半的时间内被mi预测
一句话:充其量,这可能接近数学版本——但这将取决于编译器和输入数据。除了编译器和输入数据的最偶然的组合之外,几乎可以肯定的是,它的速度至少会慢2倍,而10倍也不会有什么意外
当然,根据我使用的标志、编译器版本等,我可能能够从任一编译器获得比实际更好的结果。通过一些持久性,我甚至可能得到与代码的数学版本相同的结果。除非我对目标编译器和CPU非常了解,否则我甚至无法确定是否能得到同样好的结果,而它们更好的可能性在我看来是非常渺茫的。这通常是这样写的:
x=(x%2==0)?x*2:x代码>这是可行的,但这只是一种奇怪的方式:(x%2==0)?x*=2:0代码>只要使用如果
。最好是这样:if(is_偶数(x))x*=2代码>(即:一个函数)。如果您正在寻找模糊处理,请继续您当前的道路。如果你想让人们一眼就能理解你的代码,请留意@GManNickG的建议;如果
,则使用。这里不需要三元运算符<代码>如果(x%2==0)x*=2代码>更干净。@DavidRodríguez dribeas:请参阅编辑后的答案。一句话:从问题的语气来看,我想(尽管可能是错误的)他关心的是表现。@Jerry Cof
; mathematical version:
mov eax, DWORD PTR _x$[esp-4]
mov ecx, eax
not ecx
and ecx, 1
shl eax, cl
; Line 2
mov ecx, DWORD PTR _x$[esp-4]
mov eax, ecx
and eax, -2147483647 ; 80000001H
jns SHORT $LN5@f
dec eax
or eax, -2 ; fffffffeH
inc eax
$LN5@f:
lea eax, DWORD PTR [ecx+ecx]
je SHORT $LN1@f
; Line 3
mov eax, ecx
$LN1@f:
mov eax, DWORD PTR [ebp+8]
and eax, 1
test eax, eax
jne L2
sal DWORD PTR [ebp+8]
L2:
mov eax, DWORD PTR [ebp+8]