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

Neu*_*ino 104 c++ if-statement compilation 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.
}
Run Code Online (Sandbox Code Playgroud)

2003标准中的6.4.3节阐述了在选择语句条件中声明的变量如何具有延伸到由条件控制的子语句末尾的范围.但是我没有看到它在什么地方说不能在括号内加上括号,也没有说明每种条件只有一个声明.

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

bool a = false, b = true;

if(bool x = a || b)
{

}
Run Code Online (Sandbox Code Playgroud)

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

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

Jam*_*ton 104

我想你已经暗示过这个问题了.编译器应该如何处理这段代码?

if (!((1 == 0) && (bool a = false))) {
    // what is "a" initialized to?
Run Code Online (Sandbox Code Playgroud)

"&&"运算符是短路逻辑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?
Run Code Online (Sandbox Code Playgroud)

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

  • 我没有想到这一点.虽然在提供短路的示例中可以防止输入条件语句范围,但在这种情况下,声明varible未被处理的表达式部分不是问题,因为其范围仅限于条件语句的范围.在这种情况下,如果编译器仅在未处理声明变量的表达式的一部分时输入条件语句范围的可能性的情况下引发错误,那会不会更好?在我给出的例子中并非如此. (7认同)
  • 你解释了在if条件中有多个变量声明的所有问题,以及你只能以有限的方式使用它们的事实让我想知道为什么在地球上首先引入这种声明.在我在一些代码示例中看到之前,我从来没有感觉到需要这样的语法.我发现这种语法相当笨拙,我认为在if块之前声明变量更具可读性.如果您确实需要限制该变量的范围,可以在if块周围添加一个额外的块.我从未使用过这种语法. (5认同)
  • 好点子。您可能需要明确提及短路,以防 OP 或其他人不熟悉它。 (2认同)
  • 就个人而言,我认为能够将您正在使用的变量的范围限制在需要使用它们的语句块的范围内是相当优雅的,而不必采用诸如额外嵌套的作用域括号之类的丑陋措施. (2认同)

Mik*_*our 93

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

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

我没有看到它在什么地方说不能在括号内加上括号,也没有说明每个条件只有一个声明.

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

condition:
    expression
    type-specifier-seq declarator = assignment-expression
Run Code Online (Sandbox Code Playgroud)

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

  • 这有什么理由或背景吗? (3认同)

fwy*_*ard 48

从C++ 17开始,您最终可能会尝试做什么:

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

注意使用;而不是,分隔声明和实际条件.

  • 太好了!我总是怀疑自己超前了. (14认同)
  • 带有空增量字段的@ZeroPhase“for”语句已经提供了此构造 (4认同)
  • 如果“a”为零(短路行为),是否会调用“Func2()”? (3认同)
  • 从我读到的文档来看,是的:首先完成所有初始化,然后检查条件。 (3认同)

cra*_*str 20

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

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

    if(bool x = a || b)
    {
        //...
    }
}//a and b are out of scope
Run Code Online (Sandbox Code Playgroud)

  • +1.另外,我会将x的声明移动到周围的块:为什么它应该具有a和b的特殊状态? (5认同)

Bo *_*son 18

最后一节已经有效,你只需要写一点略有不同:

if (int a = Func1())
{
   if (int b = Func2())
   {
        // do stuff with a and b
   }
}
Run Code Online (Sandbox Code Playgroud)