我们可以将条件语句写成if
语句的形式
if (a == 5, b == 6, ... , thisMustBeTrue)
只有最后一个条件满足才能进入if
代码块。
为什么允许这样做?
我们可以将条件语句写成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(5)
是在f(6)
之前还是之后被调用。
更正式地说,逗号允许您以相同的方式编写表达式序列(a,b,c)
,就像您可以使用;
来编写语句序列a; b; c;
一样。
正如;
创建序列点(完整表达式的结尾)一样,逗号也是如此。只有序列点控制求值顺序,请参见this post。
但当然,在这种情况下,您实际上会写成这样
a = f(5);
b = f(6);
if ( thisMustBeTrue(a, b) )
那么,什么情况下逗号分隔的表达式序列比分号分隔的语句序列更可取?我想几乎从不。也许在宏中,当您希望右侧替换为单个表达式时。
简而言之:
虽然在 if
或者 while
语句的条件部分使用逗号运算符是合法的,但通常并没有意义(编辑:虽然后者有时可能会有帮助,正如 user5534870 在他的答案中所解释的那样)。
更详细的解释:
除了其语法功能(例如在初始化列表、变量声明或函数调用/声明中分隔元素),在 C 和 C++ 中,,
还可以像 +
等一样成为普通的运算符,因此可以在允许表达式的任何地方使用它(在 C++ 中甚至可以重载它)。
与大多数其他运算符不同的是,尽管两侧都会被求值,但它不会以任何方式组合左右表达式的输出,而只是返回右表达式的值。
它的引入,是因为某个人(可能是 Dennis Ritchie)认为 C 需要一种语法,在一个位置写入两个(或更多)不相关的表达式,而你通常只能写一个单独的表达式。
现在,if
语句的条件部分是(除其他外)这样的一个位置,因此你也可以在那里使用 ,
运算符——是否有意义使用它是一个完全不同的问题!特别是——与函数调用或变量声明不同——逗号在那里没有特殊的意义,因此它会评估左右表达式,但只返回右边的结果,然后由 if
语句使用。
我现在能想到只有两个点,在这两个点上使用(未重载的),
-运算符是有意义的:
如果你想在 for
循环头中同时递增多个迭代器:
for ( ... ; ... ; ++i1, ++i2){
*i2=*i1;
}
如果你想在C++11的constexpr函数中评估多个表达式。
再重申一遍:在if或while语句中使用逗号运算符——就像你在例子中展示的那样——并不是什么明智的做法。这只是C和C ++语言语法允许您编写代码的另一个例子,该代码的行为方式与人们第一眼看到它时所期望的不同。还有很多其他例子....
decltype
中,你可以将其用作简单的 SFINAE。 decltype(test_expression, void(), result_we_want)
将测试第一个表达式(确定它是否有效),如果它是有效的,则返回所需的 result_we_want
类型。参数包展开技巧 -- using discard=int[]; (void)discard{ 0, ((std::cout << ts << '\n'), void(), 0)... };
将为 ts...
参数包中的每个元素(按顺序)展开语句 std::cout << ts << '\n'
并且丢弃结果。(在这种情况下,并非所有 ,
都是逗号运算符,但是有些是) - Yakk - Adam Nevraumont对于一个 if
语句,把某些东西放到逗号表达式里面而不是外面没有实际意义。
对于一个 while
语句,将逗号表达式放到条件中会执行第一部分,要么在进入循环时执行,要么在循环时执行。 这就不能轻易地通过代码复制来复制。
那么 do
...while
语句怎么样呢? 在这里我们只需要担心循环本身,对吧? 事实证明,在这里甚至也不能安全地用逗号表达式替换移动第一部分进入循环体中。
首先,循环体中变量的析构函数此时还没有运行过,这可能会产生影响。 另外,任何在循环内的 continue
语句仅当它确实在条件中而不是在循环体中时,才会达到逗号表达式的第一部分。
没有任何优势:逗号操作符只是一个具有其表达式列表中最后一个表达式类型的表达式,并且if语句评估布尔表达式。
if(<expr>) { ... }
with type of <expr> boolean
这是一个奇怪的操作符,但没有什么魔法 - 除了它把表达式列表和函数调用中的参数列表混淆了。
foo(<args>)
with <args> := [<expr>[, <expr>]*]
请注意,在参数列表中,逗号对于分隔参数具有更强的绑定力。
void calculateValue(FooType &result) {/*...*/}
result
的条件语句呢?您可以声明将被修改的变量,然后使用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
的代码放在一个地方,并且靠近检查条件的代码行。
也许与此无关:变量通过参数传递进行更新的另一个原因是函数需要返回错误代码以及修改/返回计算出的值。在这种情况下:
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()) {
//...
}
for(..;..;..)
子句中第三个(增量)组件存在的唯一原因,我从未听说过有人抱怨那个是无用的。 - Marc van Leeuwenfor (calc(result) ; result.isBared() ; calc(result)) {...}
这样的东西,或者你有其他想法吗? - frozenkoi没有任何意义。该代码中对a
的比较是完全多余的。
void operator==(int rhs){std :: cout << rhs;}
。这是一个人们在if语句中使用“,”的代码库,我不能排除这种情况。 - Yakk - Adam Nevraumontif
或 while
语句中使用逗号的优势是什么?为什么允许这样做?for
语句中的使用是添加它们所需的原始理由。但是,通过从理论上使语言更完整,后来发现了没有人计划使用的用途。早期的 C++ 是生成 C 代码的翻译器,具有顺序表达式对于允许内联函数真正生成 C 代码中的“在线”逻辑是绝对必要的。这包括表达式出现的任何地方,包括 if
语句的条件。同样,在“有趣”的宏中也使用了它。尽管 C++ 通过提供内联函数消除了宏,但最新的编译器直到 x11 都发现 Boost FOREACH 范围循环(最终是一种模拟在 x11 中添加到语言中的功能)非常方便,并且那是一组具有魔力的巧妙宏,涉及逗号运算符。(嗯,当前版本通过链式if
/else
将其扩展为多个语句,而不是将其全部塞入单个 while
中。)现在,还有另一种方法可以将任何语句放入表达式中(lambda),因此未来模拟甚至新的语言特性或特定于领域的嵌入式语言的疯狂业务可能不需要再使用它了。if
或 while
的括号内,这可能正是合适的。在 C++ 源代码中托管的特定于领域的语言,或者是语言仿真特性,例如(也许)在嵌入式实时系统中使用的替代异常处理的方法,这可以得到证明。简而言之,并没有正常的好用法。但是为了完整性,它还是存在的,您永远不知道什么时候会有人发现它有用。
a
和b
的类型。对于用户定义的类型,可以重载operator==
并具有副作用。这种副作用可能是向您的银行账户存入一定金额的钱。考虑到这一点,您可以考虑多次调用该运算符具有优势。 - juanchopanzaoperator,()
以获得额外的乐趣! - rodrigo