C ++,'if'expression式中的variables声明
这里发生了什么?
if(int a = Func1()) { // Works. } if((int a = Func1())) { // Fails to compile. } if((int a = Func1()) && (int b = Func2())) ) { // Do stuff with a and b. // This is what I'd really like to be able to do. }
2003标准中的第6.4.3节阐述了如何在select语句条件中声明的variables的范围延伸到由条件控制的子语句的末尾。 但是,我不知道在什么地方不能在括号里面加括号,也没有在每个条件下只说一个声明。
即使在只需要一个声明的情况下,这个限制也是令人讨厌的。 考虑这个。
bool a = false, b = true; if(bool x = a || b) { }
如果我想input“if”-body作用域,并将x设置为false,则声明需要括号(因为赋值运算符的优先级低于逻辑或),但由于不能使用括号,因此需要在外部声明x显然这个例子是微不足道的,但更实际的情况是a和b是返回需要testing的值的函数
那么,我想做的是不符合标准,还是我的编译器只是把我的球(VS2008)?
if
或while
语句中的条件可以是expression式 ,也可以是单个variables声明 (带有初始化)。
你的第二个和第三个例子既不是有效的expression式,也不是有效的声明,因为声明不能构成expression式的一部分。 虽然能够像第三个例子一样编写代码会很有用,但是需要对语言语法进行重大改变。
我不知道在什么地方不能在括号里面加括号,也没有在每个条件下只说一个声明。
6.4 / 1中的语法规范给出了以下条件:
condition: expression type-specifier-seq declarator = assignment-expression
指定一个单一的声明,没有括号或其他装饰。
我想你已经暗示了这个问题。 编译器应该用这个代码做什么?
if (!((1 == 0) && (bool a = false))) { // what is "a" initialized to?
“&&”运算符是一个短路逻辑AND。 这意味着如果第一部分(1==0)
结果是错误的,那么应该不对第二部分(bool a = false)
进行评估,因为已经知道最终答案是错误的。 如果(bool a = false)
不被评估,那么稍后如何处理代码呢? 我们只是不初始化variables,并保持它不确定? 我们将它初始化为默认值? 如果数据types是一个类,并且这样做有不良副作用? 如果不是bool
而是使用了一个类,而且它没有默认的构造函数,那么用户必须提供参数 – 那么我们该怎么做呢?
这是另一个例子:
class Test { public: // note that no default constructor is provided and user MUST // provide some value for parameter "p" Test(int p); } if (!((1 == 0) && (Test a = Test(5)))) { // now what do we do?! what is "a" set to?
看起来像你发现的限制似乎是完全合理的 – 它防止了这种歧义的发生。
如果要将variables放在更窄的范围内,则可以随时使用附加的{ }
//just use { and } { bool a = false, b = true; if(bool x = a || b) { //... } }//a and b are out of scope
最后一节已经有效了,你只需要写一点不同的东西:
if (int a = Func1()) { if (int b = Func2()) { // do stuff with a and b } }
从C ++ 17开始,你试图做的事情终于可能了 :
if (int a = Func1(), b = Func2(); a && b) { // Do stuff with a and b. }
注意使用;
而不是分开声明和实际情况。
这是一个丑陋的解决方法,使用循环(如果两个variables都是整数):
#include <iostream> int func1() { return 4; } int func2() { return 23; } int main() { for (int a = func1(), b = func2(), i = 0; i == 0 && a && b; i++) { std::cout << "a = " << a << std::endl; std::cout << "b = " << b << std::endl; } return 0; }
但是这会混淆其他程序员,而且代码太差,所以不推荐。
一个简单的封闭{}
块(如已经推荐的)更容易阅读:
{ int a = func1(); int b = func2(); if (a && b) { std::cout << "a = " << a << std::endl; std::cout << "b = " << b << std::endl; } }
有一件事要注意,也是在较大的if块内的expression式
if (!((1 == 0) && (bool a = false)))
不一定保证以从左到右的方式进行评估。 编译器实际上是从右到左testing,而不是从左到右testing,这是我在当天回来的一个非常微妙的错误。
用一个小小的模板魔法,你可以解决不能声明多个variables的问题:
#include <stdio.h> template <class LHS, class RHS> struct And_t { LHS lhs; RHS rhs; operator bool () { bool b_lhs(lhs); bool b_rhs(rhs); return b_lhs && b_rhs; } }; template <class LHS, class RHS> And_t<LHS, RHS> And(const LHS& lhs, const RHS& rhs) { return {lhs, rhs}; } template <class LHS, class RHS> struct Or_t { LHS lhs; RHS rhs; operator bool () { bool b_lhs(lhs); bool b_rhs(rhs); return b_lhs || b_rhs; } }; template <class LHS, class RHS> Or_t<LHS, RHS> Or(const LHS& lhs, const RHS& rhs) { return {lhs, rhs}; } int main() { if (auto i = And(1, Or(0, 3))) { printf("%d %d %d\n", i.lhs, i.rhs.lhs, i.rhs.rhs); } return 0; }
(注意,这会影响短路评估。)