C++ 三元运算符与 if 语句的对比

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4192225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 14:47:24  来源:igfitidea点击:

Prettiness of ternary operator vs. if statement

c++if-statementternary-operator

提问by hummingBird

I'm browsing through some code and I found a few ternary operators in it. This code is a library that we use, and it's supposed to be quite fast.

我正在浏览一些代码,我在其中发现了一些三元运算符。这段代码是我们使用的一个库,它应该非常快。

I'm thinking if we're saving anything except for space there.

我在想我们是否在节省除了空间之外的任何东西。

What's your experience?

你有什么经验?

回答by Tony Delroy

Performance

表现

The ternary operator shouldn't differ in performance from a well-written equivalent if/elsestatement... they may well resolve to the same representation in the Abstract Syntax Tree, undergo the same optimisations etc..

三元运算符的性能不应与编写良好的等效if/else语句不同......它们很可能解析为抽象语法树中的相同表示,经历相同的优化等。

Things you can only do with ? :

你只能做的事情?:

If you're initialising a constant or reference, or working out which value to use inside a member initialisation list, then if/elsestatements can't be used but ?:can be:

如果您正在初始化一个常量或引用,或者确定在成员初始化列表中使用哪个值,则不能使用if/else语句,但?:可以是:

const int x = f() ? 10 : 2;

X::X() : n_(n > 0 ? 2 * n : 0) { }

Factoring for concise code

简化代码的因式分解

Keys reasons to use ?:include localisation, and avoiding redundantly repeating other parts of the same statements/function-calls, for example:

使用的关键原因?:包括本地化,以及避免重复重复相同语句/函数调用的其他部分,例如:

if (condition)
    return x;
else
    return y;

...is only preferable to...

...只比...更可取

return condition ? x : y;

...on readability grounds if dealing with very inexperienced programmers, or some of the terms are complicated enough that the ?:structure gets lost in the noise. In more complex cases like:

...如果与非常缺乏经验的程序员打交道,或者某些术语足够复杂以致于?:结构在噪音中丢失,则出于可读性的考虑。在更复杂的情况下,例如:

fn(condition1 ? t1 : f1, condition2 ? t2 : f2, condition3 ? t3 : f3);

An equivalent if/else:

等效的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...

That's a lot of extra function calls that the compiler may or may not optimise away.

这是很多额外的函数调用,编译器可能会也可能不会优化掉。

Can't named temporaries improve the if/else monstrosity above?

命名的临时变量不能改善上面的 if/else 怪物吗?

If the expressions t1, f1, t2etc. are too verbose to type repeatedly, creating named temporaries may help, but then:

如果表达式t1f1t2等太冗长重复输入,创建一个名为临时工可能会有帮助,但后来:

  • To get performance matching ?:you may need to use std::move, except when the same temporary is passed to two &&parameters in the function called: then you must avoid it. That's more complex and error-prone.

  • c?x:yevaluates cthen either but not both of xand y, which makes it safe to say test a pointer isn't nullptrbefore using it, while providing some fallback value/behaviour. The code only gets the side effects of whichever of xand yis actually selected. With named temporaries, you may need if/ elsearound or ?:inside their initialisation to unwanted code executing, or code executing more often than desired.

  • 为了获得性能匹配,?:您可能需要使用std::move,除非在&&调用的函数中将相同的临时变量传递给两个参数:那么您必须避免它。这更复杂,更容易出错。

  • c ?x :y评估c然后评估xy 之一,但不能同时评估xy,这使得可以安全地说nullptr在使用指针之前不是测试指针,同时提供一些后备值/行为。该代码仅获得实际选择的xy 中的任何一个的副作用。使用命名临时文件时,您可能需要if/else周围或?:内部对不需要的代码执行进行初始化,或者代码执行的频率高于预期。

Functional difference: unifying result type

功能区别:统一结果类型

Consider:

考虑:

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);
}

In the conditional operator version above, 1undergoes a Standard Conversion to doubleso that the type matched 2.0, meaning the is(double)overload is called even for the true/1situation. The if/elsestatement doesn't trigger this conversion: the true/1branch calls is(int).

在上面的条件运算符版本中,1经过标准转换为double使类型匹配2.0,这意味着is(double)即使在true/1情况下也会调用重载。该if/else语句不触发这个转换:在true/1分支呼叫is(int)

You can't use expressions with an overall type of voidin a conditional operator either, whereas they're valid in statements under an if/else.

您也不能void在条件运算符中使用整体类型为 of 的表达式,而它们在if/下的语句中有效else

Emphasis: value-selection before/after action needing values

重点:在需要价值的行动之前/之后进行价值选择

There's a different emphasis:

有不同的强调:

An if/elsestatement emphasises the branching first and what's to be done is secondary, while a ternary operator emphasises what's to be done over the selection of the values to do it with.

一个if/else声明强调第一的分支,什么是必须做的是次要的,而三元运营商强调什么是所有的值,做它的选择要做。

In different situations, either may better reflect the programmer's "natural" perspective on the code and make it easier to understand, verify and maintain. You may find yourself selecting one over the other based on the order in which you consider these factors when writing the code - if you've launched into "doing something" then find you might use one of a couple (or few) values to do it with, ?:is the least disruptive way to express that and continue your coding "flow".

在不同的情况下,要么可以更好地反映程序员对代码的“自然”观点,并使其更易于理解、验证和维护。您可能会发现自己根据在编写代码时考虑这些因素的顺序来选择一个而不是另一个 - 如果您已经开始“做某事”,那么您可能会使用几个(或几个)值中的一个来做它与,?:是表达这一点并继续您的编码“流程”的最少破坏性方式。

回答by thkala

Well...

好...

I did a few tests with GCC and this function call:

我用 GCC 和这个函数调用做了一些测试:

add(argc, (argc > 1)?(argv[1][0] > 5)?50:10:1, (argc > 2)?(argv[2][0] > 5)?50:10:1, (argc > 3)?(argv[3][0] > 5)?50:10:1);

The resulting assembler code with gcc -O3 had 35 instructions.

生成的带有 gcc -O3 的汇编代码有 35 条指令。

The equivalent code with if/else + intermediate variables had 36. With nested if/else using the fact that 3 > 2 > 1, I got 44. I did not even try to expand this into separate function calls.

if/else + 中间变量的等效代码有 36 个。使用嵌套 if/else 使用 3 > 2 > 1 的事实,我得到了 44。我什至没有尝试将其扩展为单独的函数调用。

Now I did not do any performance analysis, nor did I do a quality check of the resulting assembler code, but at something simple like this with no loops e.t.c. I believe shorter is better.

现在我没有做任何性能分析,也没有对生成的汇编代码进行质量检查,但是在像这样没有循环等简单的事情上,我相信越短越好。

It appears that there is some value to ternary operators after all :-)

毕竟,三元运算符似乎有一些价值:-)

That is only if code speed is absolutely crucial, of course. If/else statements are much easier to read when nested than something like (c1)?(c2)?(c3)?(c4)?:1:2:3:4. And having huge expressions as function arguments is notfun.

当然,只有在代码速度绝对至关重要的情况下。嵌套时 if/else 语句比 (c1)?(c2)?(c3)?(c4)?:1:2:3:4 更容易阅读。将巨大的表达式作为函数参数并不好玩。

Also keep in mind that nested ternary expressions make refactoring the code - or debugging by placing a bunch of handy printfs() at a condition - a lot harder.

还要记住,嵌套的三元表达式使得重构代码——或者通过在条件中放置一堆方便的 printfs() 来调试——要困难得多。

回答by Flexo

The only potential benefit to ternary operators over plain if statements in my view is their ability to be used for initializations, which is particularly useful for const:

在我看来,三元运算符对普通 if 语句的唯一潜在好处是它们能够用于初始化,这对于以下情况特别有用const

E.g.

例如

const int foo = (a > b ? b : a - 10);

Doing this with an if/else block is impossible without using a function cal as well. If you happen to have lots of cases of const things like this you might find there's a small gain from initializing a const properly over assignment with if/else. Measure it! Probably won't even be measurable though. The reason I tend to do this is because by marking it const the compiler knows when I do something later that could/would accidentally change something I thought was fixed.

如果不使用函数 cal 也无法使用 if/else 块执行此操作。如果您碰巧有很多像这样的 const 情况,您可能会发现通过使用 if/else 正确初始化 const 会带来一些好处。测量它!虽然可能甚至无法衡量。我倾向于这样做的原因是因为通过将它标记为 const 编译器知道我以后什么时候做一些可能/会意外更改我认为已修复的事情。

Effectively what I'm saying is that ternary operator is important for const-correctness, and const correctness is a great habit to be in:

实际上,我要说的是三元运算符对于常量正确性很重要,而常量正确性是一个很好的习惯:

  1. This saves a lot of your time by letting the compiler help you spot mistakes you make
  2. This can potentially let the compiler apply other optimizations
  1. 通过让编译器帮助您发现所犯的错误,这可以节省您的大量时间
  2. 这可能会让编译器应用其他优化

回答by Flexo

You assume that there must bea distinction between the two when, in fact, there are a number of languages which forgo the "if-else" statement in favor of an "if-else" expression (in this case, they may not even have the ternary operator, which is no longer needed)

您假设两者之间必须有区别,事实上,有许多语言放弃了“if-else”语句而支持“if-else”表达式(在这种情况下,它们甚至可能不有不再需要的三元运算符)

Imagine:

想象:

x = if (t) a else b

Anyway, the ternary operator is an expression in some languages (C,C#,C++,Java,etc) which do nothave "if-else" expressions and thus it serves a distinct rolethere.

无论如何,三元运算符是某些语言(C、C#、C++、Java 等)中没有“if-else”表达式的表达式,因此它那里扮演着独特的角色

回答by Sean

If you're worried about it from a performance perspective then I'd be very surprised if there was any different between the two.

如果您从性能的角度担心它,那么如果两者之间有任何不同,我会感到非常惊讶。

From a look 'n feel perspective it's mainly down to personal preference. If the condition is short and the true/false parts are short then a ternary operator is fine, but anything longer tends to be better in an if/else statement (in my opinion).

从外观的角度来看,这主要取决于个人喜好。如果条件很短并且真/假部分很短,那么三元运算符就可以了,但是在 if/else 语句中,任何更长的东西往往会更好(在我看来)。