条件语句中逗号的优点是什么?

Abd*_*man 60 c++ if-statement comma

我们可以写一个if声明

if (a == 5, b == 6, ... , thisMustBeTrue)
Run Code Online (Sandbox Code Playgroud)

只有最后一个条件才能进入if身体.

为什么允许?

Jon*_*ger 67

稍微改变你的例子,假设是这样的

if ( a = f(5), b = f(6), ... , thisMustBeTrue(a, b) )
Run Code Online (Sandbox Code Playgroud)

(注意=而不是==).在这种情况下,逗号保证从左到右的评估顺序.与此形成鲜明对比

if ( thisMustBeTrue(f(5), f(6)) )
Run Code Online (Sandbox Code Playgroud)

你不知道f(5)之前或之后是否被召唤过f(6).

更正式,逗号让你写一个序列表达式(a,b,c)中,你可以用同样的方法;写的语句序列a; b; c;.就像;创建一个序列点(完整表达的结束)一样,逗号也是如此.只有序列点控制评估顺序,请参阅此文章.

但是,当然,在这种情况下,你实际上是写这个

a = f(5);
b = f(6);    
if ( thisMustBeTrue(a, b) )
Run Code Online (Sandbox Code Playgroud)

那么,逗号分隔的表达式序列何时优先于;分离的语句序列?我几乎不会说.当您希望右侧替换为单个表达式时,也许在宏中.


Mik*_*eMB 44

简而言之: 尽管这样做是合法的,但在一个ifwhile语句的条件部分使用逗号运算符通常没有意义(编辑:虽然后者有时可能会有用,因为用户5534870在他的回答中解释).

更详细的解释: 除了它的语法功能(例如,分隔初始化列表中的元素,变量声明或函数调用/声明),在C和C++中,,也可以像普通的运算符一样+,因此它可以在任何地方使用,允许表达式(在C++中你甚至可以重载它).
与大多数其他运算符的不同之处在于 - 虽然双方都得到了评估 - 但它并没有以任何方式组合左右表达式的输出,而只返回正确的表达式.
之所以介绍,是因为有人(可能是Dennis Ritchie)因某种原因决定C需要一个语法来在一个位置写两个(或更多)不相关的表达式,你通常只能写一个表达式.

现在,if声明的条件是(以及其他)这样的地方,因此,你也可以在,那里使用运算符 - 这样做是否有意义是一个完全不同的问题!特别是 - 与函数调用或变量声明不同 - 逗号在那里没有特殊含义,所以它总是这样做:它左右计算表达式,但只返回正确的结果,然后由if声明使用.

我现在能想到的唯一两点,使用(非重载) - ,运算符是有意义的:

  1. 如果要在for循环的头部增加多个迭代器:

    for ( ... ; ... ; ++i1, ++i2){
        *i2=*i1;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果要在C++ 11 constexpr函数中计算多个表达式.

要再次重复这一点:在一个ifwhile语句中使用逗号运算符- 就像你在你的例子中展示它一样 - 不是明智之举.这只是另一个例子,C和C++的语言语法允许你编写代码,这种代码的行为方式不像第一眼看到的那样.还有更多....

  • @Abdul:嗯,因为你必须选择一个,有人决定它应该是最后一个.您必须了解,与在代码中的其他位置使用逗号运算符相比,逗号运算符在if语句中没有任何特殊行为. (12认同)

小智 15

对于一个if声明,将某些东西放入逗号表达式而不是外部是没有意义的.

对于while语句,将逗号表达式放入条件在进入循环时循环时执行第一部分.如果没有代码重复,就无法轻松复制.

那么do...... while陈述怎么样?我们只需要担心循环本身,对吧?事实证明,即使在这里,也可以通过将第一部分移动到循环中来安全地替换逗号表达式.

首先,循环体中变量的析构函数将不会被运行,这可能会产生影响.另一方面,continue循环内的任何语句只有在确实处于条件而不是循环体中时才会到达逗号表达式的第一部分.

  • 也许你可以添加一些代码示例?就目前而言,这不仅仅是令人困惑. (3认同)

Bey*_*ios 10

没有优势:逗号运算符只是一个表达式,其表达式列表中包含最后一个表达式的类型,if语句计算布尔表达式.

if(<expr>) { ... }
 with type of <expr> boolean
Run Code Online (Sandbox Code Playgroud)

这是一个奇怪的运算符,但它没有任何魔力 - 除了它在函数调用中混淆了表达式列表和参数列表.

foo(<args>)
 with <args> := [<expr>[, <expr>]*]
Run Code Online (Sandbox Code Playgroud)

请注意,在参数列表中,逗号与分隔参数的绑定更强.

  • 我想我们都同意逗号表达式是不必要的;)在for循环的情况下,初始化和增量的语法可能只是一个语句列表而不是表达式,我们不会有这种混淆. . (3认同)

fro*_*koi 7

接下来是有点延伸,取决于你可能希望的那种狡猾.

考虑一下函数通过修改通过引用或通过指针传递的参数(可能来自设计糟糕的库,或者确保在返回后不被分配而忽略该值,无论如何)来返回值的情况.

void calculateValue(FooType &result) {/*...*/}
Run Code Online (Sandbox Code Playgroud)

那么你如何使用依赖的条件语句result

您可以声明要修改的变量,然后使用if检查:

FooType result;
calculateValue(result);
if (result.isBared()) {
    //...
}
Run Code Online (Sandbox Code Playgroud)

这可以缩短为

FooType result;
if (calculateValue(result) , result.isBared()) {
    //...
}
Run Code Online (Sandbox Code Playgroud)

这不值得.但是,对于while循环,可能会有一些小的优点.如果calculateValue应该/可以调用,直到结果不再是bar'd,我们会有类似的东西:

FooType result;
calculateValue(result);  //[1] Duplicated code, see [2]
while (result.isBared()) {
    //... possibly many lines
    //separating the two places where result is modified and tested

    //How do you prevent someone coming after you and adds a `continue`
    //here which prevents result to be updated in the and of the loop?

    calculateValue(result); //[2] Duplicated code, see [1]
}
Run Code Online (Sandbox Code Playgroud)

并可以浓缩为:

FooType result;
while (calculateValue(result) , result.isBared()) {
    //all your (possibly numerous) code lines go here
}
Run Code Online (Sandbox Code Playgroud)

这样,要更新的代码result只在一个地方,并且接近检查其条件的行.

可能不相关:变量可以通过参数传递更新的另一个原因是除了修改/返回计算值之外,函数还需要返回错误代码.在这种情况下:

ErrorType fallibleCalculation(FooType &result) {/*...*/}
Run Code Online (Sandbox Code Playgroud)

然后

FooType result;
ErrorType error;

while (error = fallibleCalculation(result) , (Success==error && result.isBared())) {
    //...
}
Run Code Online (Sandbox Code Playgroud)

但正如评论中所述,你也可以不用逗号来做到这一点:

FooType result;
ErrorType error;

while (Success == fallibleCalculation(result) && result.isBared()) {
    //...
}
Run Code Online (Sandbox Code Playgroud)