C ++,'if'表达式中的变量声明

时间:2011-10-20 13:44:36

标签: c++ compilation if-statement variable-declaration

这里发生了什么?

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节说明了在选择语句条件中声明的变量如何具有延伸到由条件控制的子语句末尾的范围。但我没有看到它在什么地方说不能在括号内加上括号,也没有说明每个条件只有一个声明。

即使在条件中只需要一个声明的情况下,这个限制也很烦人。考虑一下。

bool a = false, b = true;

if(bool x = a || b)
{

}

如果我想在x设置为false的情况下输入'if“-body范围,则声明需要括号(因为赋值运算符的优先级低于逻辑OR),但由于括号不能使用,因此需要声明在身体之外的x,将该声明泄露到比预期更大的范围。显然这个例子是微不足道的,但更现实的情况是a和b是返回需要测试的值的函数

那么我想要做的是不符合标准,还是我的编译器只是破坏了我的球(VS2008)?

8 个答案:

答案 0 :(得分:99)

我想你已经暗示了这个问题。编译器应该对此代码做什么?

if (!((1 == 0) && (bool a = false))) {
    // what is "a" initialized to?

“&&”运算符是一个短路逻辑AND。这意味着如果第一部分(1==0)结果为假,则不应评估第二部分(bool a = false),因为已知最终答案将为假。如果未评估(bool a = false),那么稍后使用a如何处理代码?我们不会初始化变量并保持未定义吗?我们会将其初始化为默认值吗?如果数据类型是一个类并且这样做会产生不良副作用怎么办?如果您使用的是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?

似乎你发现的限制似乎完全合理 - 它可以防止这些歧义发生。

答案 1 :(得分:90)

ifwhile语句中的条件可以是表达式,也可以是单个变量声明(带初始化)。< / p>

您的第二个和第三个示例既不是有效的表达式,也不是有效的声明,因为声明不能构成表达式的一部分。虽然能够像第三个例子那样编写代码是有用的,但它需要对语言语法进行重大更改。

  

我没有看到任何关于不能在声明中加上括号的内容,也没有说明每个条件只有一个声明。

6.4 / 1中的语法规范给出了以下条件:

condition:
    expression
    type-specifier-seq declarator = assignment-expression

指定单个声明,没有括号或其他装饰。

答案 2 :(得分:36)

从C ++ 17开始,您尝试做is finally possible

if (int a = Func1(), b = Func2(); a && b)
{
    // Do stuff with a and b.
}

请注意使用;代替,来分隔声明和实际情况。

答案 3 :(得分:19)

如果要将变量括在较窄的范围内,可以随时使用其他{ }

//just use { and }
{
    bool a = false, b = true;

    if(bool x = a || b)
    {
        //...
    }
}//a and b are out of scope

答案 4 :(得分:18)

最后一节已经有效,你只需稍微改写一下:

if (int a = Func1())
{
   if (int b = Func2())
   {
        // do stuff with a and b
   }
}

答案 5 :(得分:2)

这是一个使用循环的丑陋解决方法(如果两个变量都是整数):

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

答案 6 :(得分:1)

有一点需要注意的是,较大的if-block

中的表达式
if (!((1 == 0) && (bool a = false)))

不一定保证以从左到右的方式进行评估。我当天回到的一个相当微妙的错误与编译器实际上是从右到左而不是从左到右进行测试的事实有关。

答案 7 :(得分:0)

使用一点模板魔法,您可以解决无法声明多个变量的问题:

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

(注意,这会使短路评估失效。)