表现
三元运算符的性能与编写良好的等效运算符不应有差异if
/else
声明...它们很可能解析为抽象语法树中的相同表示,进行相同的优化等。
你只能用它来做的事情? :
如果您正在初始化常量或引用,或者计算出在成员初始化列表中使用哪个值,那么if
/else
不能使用语句,但是?
:
can be:
const int x = f() ? 10 : 2;
X::X() : n_(n > 0 ? 2 * n : 0) { }
简洁代码的分解
按键使用理由?
:
包括本地化,并避免冗余地重复相同语句/函数调用的其他部分,例如:
if (condition)
return x;
else
return y;
...只比...更好
return condition ? x : y;
...如果与非常缺乏经验的程序员打交道,或者某些术语足够复杂,则出于可读性的考虑?
:
结构在噪音中消失。在更复杂的情况下,例如:
fn(condition1 ? t1 : f1, condition2 ? t2 : f2, condition3 ? t3 : f3);
同等的if
/else
:
if (condition1)
if (condition2)
if (condition3)
fn(t1, t2, t3);
else
fn(t1, t2, f3);
else if (condition3)
fn(t1, f2, t3);
else
fn(t1, f2, f3);
else
if (condition2)
...etc...
这是编译器可能会也可能不会优化的大量额外函数调用。
更远,?
允许您选择一个对象,然后使用其中的成员:
(f() ? a : b).fn(g() ? c : d).field_name);
相当于if
/else
将会:
if (f())
if (g())
x.fn(c.field_name);
else
x.fn(d.field_name);
else
if (g())
y.fn(c.field_name);
else
y.fn(d.field_name);
命名临时变量不能改善上面的 if/else 问题吗?
如果表达式t1
, f1
, t2
等太冗长而无法重复输入,创建命名临时变量可能会有所帮助,但是:
获得性能匹配?
:
你可能需要使用std::move
,除非将相同的临时值传递给两个&&
被调用函数中的参数:那么你必须避免它。这更加复杂并且容易出错。
c ?
x :
y评估c那么其中之一但不是两者x and y,这使得可以肯定地说测试指针不是nullptr
在使用它之前,同时提供一些后备值/行为。该代码仅获得以下任一者的副作用x and y实际上是被选中的。对于命名临时对象,您可能需要if
/ else
周围或?
:
在它们的初始化中,以防止执行不需要的代码,或者代码执行的频率超过预期。
功能差异:统一结果类型
考虑:
void is(int) { std::cout << "int\n"; }
void is(double) { std::cout << "double\n"; }
void f(bool expr)
{
is(expr ? 1 : 2.0);
if (expr)
is(1);
else
is(2.0);
}
在上面的条件运算符版本中,1
经过标准转换为double
使类型匹配2.0
,意味着is(double)
即使对于true
/1
情况。这if
/else
语句不会触发此转换:true
/1
分行呼叫is(int)
.
您不能使用具有整体类型的表达式void
在条件运算符中,而它们在条件运算符下的语句中有效if
/else
.
强调:需要值的行动之前/之后的值选择
有不同的侧重点:
An if
/else
语句首先强调分支,而要做什么是次要的,而三元运算符则强调要做什么而不是选择要执行的值。
在不同的情况下,两者都可能更好地体现程序员对代码的“自然”视角,并使其更易于理解、验证和维护。您可能会发现自己根据编写代码时考虑这些因素的顺序来选择其中一个 - 如果您已经开始“做某事”,那么您可能会使用几个(或几个)值中的一个来执行操作它与,?
:
是表达这一点并继续编码“流程”的破坏性最小的方式。