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

发布于 2024-12-11 04:17:17 字数 695 浏览 0 评论 0原文

这是怎么回事?

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”主体范围,则声明需要括号(因为赋值运算符的优先级低于逻辑 OR),但由于不能使用括号,因此需要在外部声明 x主体,将该声明泄漏到比预期更大的范围。显然这个例子很简单,但更现实的情况是 a 和 b 是返回需要测试的值的函数,

这就是我想要做的不符合标准的事情,或者我的编译器只是破坏了我的球(VS2008 )?

What's going on here?

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.
}

Section 6.4.3 in the 2003 standard explains how variables declared in a selection statement condition have scope that extends to the end of the substatements controlled by the condition. But I don't see where it says anything about not being able to put parenthesis around the declaration, nor does it say anything about only one declaration per condition.

This limitation is annoying even in cases where only one declaration in the condition is required. Consider this.

bool a = false, b = true;

if(bool x = a || b)
{

}

If I want to enter the 'if'-body scope with x set to false then the declaration needs parenthesis (since the assignment operator has lower precedence than the logical OR), but since parenthesis can't be used it requires declaration of x outside the body, leaking that declaration to a greater scope than is desired. Obviously this example is trivial but a more realistic case would be one where a and b are functions returning values that need to be tested

So is what I want to do non-conformant to the standard, or is my compiler just busting my balls (VS2008)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

做个少女永远怀春 2024-12-18 04:17:17

从 C++17 开始,您尝试做的事情终于可能

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

:使用 ; 代替 , 来分隔声明和实际条件。

As of C++17 what you were trying to do is finally possible:

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

Note the use of ; of instead of , to separate the declaration and the actual condition.

痴情换悲伤 2024-12-18 04:17:17

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

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

“&&”运算符是短路逻辑 AND。这意味着如果第一部分 (1==0) 结果为 false,则不应评估第二部分 (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?

看起来您发现的限制似乎完全合理 - 它可以防止此类歧义的发生。

I think you already hinted at the issue. What should the compiler do with this code?

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

The "&&" operator is a short-circuit logical AND. That means that if the first part (1==0) turns out to be false, then the second part (bool a = false) should be not be evaluated because it is already known that the final answer will be false. If (bool a = false) isn't evaluated, then what to do with code later on that uses a? Would we just not initialize the variable and leave it undefined? Would we initialize it to the default? What if the data type was a class and doing this had undesirable side effects? What if instead of bool you used a class and it had no default constructor such that the user must provide parameters - what do we do then?

Here's another example:

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?

Seems like the limitation you have found seems perfectly reasonable - it prevents these kinds of ambiguities from happening.

单调的奢华 2024-12-18 04:17:17

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

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

我没有看到它在哪里说不能在声明两边加上括号,也没有说每个条件只能有一个声明。

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

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

指定单个声明,不带括号或其他装饰。

The condition in an if or while statement can be either an expression, or a single variable declaration (with initialisation).

Your second and third examples are neither valid expressions, nor valid declarations, since a declaration can't form part of an expression. While it would be useful to be able to write code like your third example, it would require a significant change to the language syntax.

I don't see where it says anything about not being able to put parenthesis around the declaration, nor does it say anything about only one declaration per condition.

The syntax specification in 6.4/1 gives the following for the condition:

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

specifying a single declaration, with no parentheses or other adornments.

人生百味 2024-12-18 04:17:17

如果您想将变量包含在更窄的范围内,您可以随时使用附加的 { }

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

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

If you want to enclose variables in a narrower scope, you can always use additional { }

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

    if(bool x = a || b)
    {
        //...
    }
}//a and b are out of scope
荒岛晴空 2024-12-18 04:17:17

最后一部分已经可以工作了,你只需要把它写得稍有不同:

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

The last section already works, you just have to write it slightly different:

if (int a = Func1())
{
   if (int b = Func2())
   {
        // do stuff with a and b
   }
}
怪我闹别瞎闹 2024-12-18 04:17:17

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

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

Here's an ugly workaround using a loop (if both variables are integers):

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

But this will confuse other programmers and it's rather bad code, so not recommended.

A simple enclosing {} block (as already recommended) is much easier to read:

{
    int a = func1();
    int b = func2();

    if (a && b)
    {
        std::cout << "a = " << a << std::endl;
        std::cout << "b = " << b << std::endl;
    }
}
微暖i 2024-12-18 04:17:17

还需要注意的一件事是,较大的 if 块内的表达式

if (!((1 == 0) && (bool a = false)))

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

One thing to note, also is that the expressions inside the larger if-block

if (!((1 == 0) && (bool a = false)))

are not necessarily guaranteed to be evaluated in a left-to-right fashion. One rather subtle bug that I had back in the day had to do with the fact that the compiler was actually testing right-to-left instead of left-to-right.

抱猫软卧 2024-12-18 04:17:17

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

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

注意,这会丢失短路评估。)

With a little template magic you can kind of sort of get around the problem of not being able to declare multiple 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;
}

(Note, this looses the short circuit evaluation.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文