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

我们可以写一个if语句

 if (a == 5, b == 6, ... , thisMustBeTrue) 

只有最后一个条件才可以进入if体。

为什么允许?

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

 if ( a = f(5), b = f(6), ... , thisMustBeTrue(a, b) ) 

(注意=而不是== )。 在这种情况下,逗号保证从左到右的评估顺序。 相反,与此

 if ( thisMustBeTrue(f(5), f(6)) ) 

你不知道在f(6)之前或之后是否调用f(6)

更正式的说,逗号允许你用同样的方式写一个expression式(a,b,c) 写一个陈述序列a; b; c; a; b; c; 。 就像一个; 创build一个序列点 (完整expression式的结尾),逗号也一样。 只有顺序点pipe理评估的顺序,看到这个职位 。

当然,在这种情况下,你实际上是这样写的

 a = f(5); b = f(6); if ( thisMustBeTrue(a, b) ) 

所以,当一个逗号分隔的expression式序列更喜欢a ; 分开的语句序列? 我几乎从不说。 也许在macros观上,当你希望右边的replace是一个单一的expression式。

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

一个更详细的解释:除了它的语法function(例如,在初始化列表,variables声明或函数调用/声明中分离元素),在C和C ++中,它们也可以像普通的运算符一样,所以它可以是在任何地方都可以使用expression式(在C ++中,甚至可以重载)。
与大多数其他操作符的不同之处在于,尽pipe双方都得到了评估,但它并不以任何方式组合左右expression式的输出,只是返回正确的结果。
它被引入了,因为有人(可能是Dennis Ritchie)由于某种原因决定了C需要一个语法来在一个位置写两个(或更多)不相关的expression式,通常只能写一个expression式。

现在, if语句的条件是(除其他之外)这样一个地方,因此,你也可以在那里使用,操作符 – 这样做是否合理是一个完全不同的问题! 特别是 – 与例如函数调用或variables声明不同,逗号在那里没有特殊的含义,所以它总是这样做:它将expression式评估到左侧和右侧,只是返回正确的结果,然后由if语句使用。

我现在可以想到的只有两点:使用( 非重载 )操作符的意义在于:

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

     for ( ... ; ... ; ++i1, ++i2){ *i2=*i1; } 
  2. 如果要在C ++ 11 constexpr函数中评估多个expression式。

再次重复一遍:在ifwhile语句中使用逗号运算符 – 以您在示例中显示的方式 – 不是明智的做法。 这只是C和C ++的语言语法允许你编写代码的另一个例子,它并不像一个乍看之下那样行事。 还有更多….

对于if语句,将某些东西放入逗号expression式而不是外部是没有意义的。

对于while语句,将逗号expression式放入条件中在进入循环循环时执行第一部分。 没有代码重复就不容易复制。

那么如何… …声明呢? 我们只需要担心循环本身,对吧? 事实certificate,即使在这里,一个逗号expression式也不能通过将第一部分移动到循环中来安全地replace。

首先,循环体中的variables的析构函数将不会被运行,这可能会有所作为。 另一方面,循环内的任何continue语句只有在确实处于条件而不是循环体时才会到达逗号expression式的第一部分。

没有优势 :逗号运算符只是expression式列表中最后一个expression式types的expression式,if语句计算布尔expression式。

 if(<expr>) { ... } with type of <expr> boolean 

这是一个奇怪的操作符是真实的,但它没有什么魔力 – 除了在函数调用中混淆expression式列表和参数列表。

 foo(<args>) with <args> := [<expr>[, <expr>]*] 

请注意,在参数列表中,逗号与分隔参数的关系更强。

接下来的是一段时间,取决于你可能希望成为多么狡猾。

考虑一个函数通过修改一个由引用传递的参数或通过一个指针(可能来自一个devise错误的库,或者为了确保这个值在返回后不被忽略而不被忽略)而返回一个值的情况。

 void calculateValue(FooType &result) {/*...*/} 

那么如何使用依赖于result条件语句呢?

你可以声明将被修改的variables,然后用if来检查它:

 FooType result; calculateValue(result); if (result.isBared()) { //... } 

这可以缩短到

 FooType result; if (calculateValue(result) , result.isBared()) { //... } 

这不是真的值得。 但是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] } 

可以凝结成:

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

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

也许不相关:variables可以通过parameter passing更新的另一个原因是函数需要返回错误代码,除了修改/返回计算的值。 在这种情况下:

 ErrorType fallibleCalculation(FooType &result) {/*...*/} 

然后

 FooType result; ErrorType error; while (error = fallibleCalculation(result) , (Success==error && result.isBared())) { //... } 

但正如在评论中指出的那样,你也可以在没有逗号的情况下做到这一点:

 FooType result; ErrorType error; while (Success == fallibleCalculation(result) && result.isBared()) { //... } 

没有任何。 该代码中的比较是完全多余的。

我的问题是在ifwhile语句中逗号的优点是什么? 为什么允许?

它的存在是因为语句和expression式在C中是不同的东西。复合expression式是一种从理论(和其他一些语言)理解的构造,如果没有以逗号的forms添加它,它将会丢失。 它在声明中的使用是他们为什么需要它的原始理由。

但是,从理论的angular度来看,使语言更加完整,后来发现了没有人计划的用途。 早期的C ++是生成C作为输出的翻译器,并且具有顺序expression式对于允许内联函数在C代码中真正生成“在线”逻辑是绝对必要的。

这包括expression式出现的任何地方, 包括 if语句的条件。

同样,它已被用在“有趣”的macros中。 就像C ++通过提供内联函数来消除macros一样,迟到的x11编译器发现Boost FOREACH范围循环(最终,仿真x11中添加的语言特性)非常方便,那就是一个与逗号运算符有关的非常聪明的macros。

(嗯,当前的版本使用链接的if / else扩展为多个语句,而不是将它们全部拼凑成一个单一的。)

现在,还有另外一种方法可以将任何语句放入expression式(lambdas)中,所以未来疯狂的模拟更新的语言特性或特定于领域的embedded式语言的macros可能不再需要使用该语言。


所以,不要这样写代码。 除非写出帮助函数或分割成多个语句,这很简单。

但是,对于一个想在一个地方轻松使用的macros而言,这可能只是一件事情,而这个地方就在一个ifwhile 。 这可以在C ++源代码中托pipe的特定领域的语言或者embedded式实时系统中使用的语言仿真function (可能是替代exception处理)来certificate是合理的。

总之,它没有一个正常的使用。 但它是完整的,你永远不知道什么时候有人会发现它有用。