Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/153.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;,'中的变量声明;如果';表达_C++_Compilation_If Statement_Variable Declaration - Fatal编程技术网

C++ C++;,'中的变量声明;如果';表达

C++ C++;,'中的变量声明;如果';表达,c++,compilation,if-statement,variable-declaration,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年标

这是怎么回事

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)?

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

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?

您发现的限制似乎非常合理-它可以防止此类歧义的发生。

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

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

我看不出它在哪里说不能在声明周围加括号,也没有说每个条件只有一个声明

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

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

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

如果要将变量包含在较窄的范围内,则始终可以使用附加的
{}

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

需要注意的一点是,较大的if块中的表达式

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

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

有了一点模板魔术,你可以在某种程度上绕过无法声明多个变量的问题:

#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;
}
#包括
模板
结构和{
LHS-LHS;
RHS RHS;
运算符bool(){
布尔布尔布尔豪斯(lhs);
布尔布尔布尔区(rhs);
返回左前和右前;
}
};
模板
和(const-LHS&LHS,const-RHS&RHS){return{LHS,RHS};}
模板
结构或{
LHS-LHS;
RHS RHS;
运算符bool(){
布尔布尔布尔豪斯(lhs);
布尔布尔布尔区(rhs);
返回b|U lhs | b|U rhs;
}
};
模板
或(常量LHS&LHS,常量RHS&RHS){return{LHS,RHS};}
int main(){
如果(自动i=和(1,或(0,3))){
printf(“%d%d%d\n”,i.lhs,i.rhs.lhs,i.rhs.rhs);
}
返回0;
}

(注意,这会减少短路评估。)

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


从C++17开始,您要做的是:


注意
的用法
而不是
来分隔声明和实际条件。

“如果我想用“@crashmstr:true”进入循环,但是
while
的条件与
If
的条件相同。这不能用逗号运算符完成吗?我的意思是:
如果(inta=foo(),intb=bar(),a&b)
?如果未重载逗号运算符,则标准表示表达式从左到右求值,结果值为最后一个表达式。它可以与
一起进行
循环初始化,为什么不在这里呢?@Archie:我刚刚试过,我无法让它工作。也许你可以提供一个有效的例子?@JamesJohnston:我也试过了,但似乎不起作用。这个想法来自我的头脑,我是根据
if
的工作原理提出的,这似乎是一个错误的假设。这一点很好。你可能想明确提到短路,以防OP或其他人不熟悉。我没有想到这一点。虽然在您提供的示例中,短路会阻止输入条件语句范围,但在这种情况下,表达式中声明未处理变量的部分不是问题,因为其范围仅限于条件语句的范围。在哪种情况下,如果编译器只在声明变量的表达式的一部分未被处理时可能输入条件语句范围的情况下才引发错误,不是更好吗?在我给出的例子中,情况并非如此。@中微子乍一看,你的想法听起来有点像SAT问题,但事实并非如此
#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 (int a = Func1(), b = Func2(); a && b)
{
    // Do stuff with a and b.
}