C++ 如何在if语句的括号中声明变量?

C++ 如何在if语句的括号中声明变量?,c++,c++11,C++,C++11,我想在if语句的括号中声明一个局部变量。 比如说 if((char c = getc(stdin)) == 0x01)//This is not OK with g++. { ungetc(c, stdin); } 我想要的是,看看这个角色是否是我想要的。 一般来说,我希望在if行和if体中使用变量(char c),但不要在if外部使用 但是g++(GCC4.8.1)在“char”之前表示预期的主表达式。 我想知道是否有办法做到这一点,因为我不想要像这样的东西 char c = get

我想在if语句的括号中声明一个局部变量。 比如说

if((char c = getc(stdin)) == 0x01)//This is not OK with g++.
{
    ungetc(c, stdin);
}
我想要的是,看看这个角色是否是我想要的。 一般来说,我希望在if行和if体中使用变量(char c),但不要在if外部使用

但是g++(GCC4.8.1)在“char”之前表示预期的主表达式。 我想知道是否有办法做到这一点,因为我不想要像这样的东西

char c = getc(stdin);
if(c == 0x01)
{
    bla...
}

直到看到一些发布的解决方案之后,我才知道如何创建一个变量并使用
if
测试它的值。但是,您可以使用
开关
。这将允许您对附加值做出反应(可能是
EOF
):

您可以将
if
语句放在一个内联函数中,代码看起来会更干净一些。如果您确实希望源代码位于该位置,但不需要在带有新变量的
If
周围创建新范围,那么lambda可能是您可以接受的

[](int c){ if (c == 0x01) ungetc(c, stdin); }(getc(stdin));
由于您仅与一个值进行比较,您的特定问题根本不需要变量,因此您可以简单地执行以下操作:

if (getc(stdin) == 0x01) {
    char c = 0x01;
    ungetc(c, stdin); //or bla...
}
如果要与一组值进行比较,则
开关
建议是更好的选择

Jerry Coffin的解决方案看起来很吸引人,但实际上可以归结为:

if (int c = (getc(stdin) == 0x01)) //...
这可能不是您真正想要的,因为如果您想要与不同于
0x01
的值进行比较,它的通用性不好

Potatoswatter的解决方案似乎更接近您想要的,但将类型拉到独立类中可能会更好:

template <typename T>
class SetAndTest {
    const T test_;
    T set_;
public:
    SetAndTest (T s = T(), T t = T()) : set_(s), test_(t) {}
    operator bool () { return set_ == test_; }
    operator bool () const { return set_ == test_; }
    operator T & () { return set_; }
    operator T () const { return set_; }
};

//...
if (auto c = SetAndTest<int>(getc(stdin), 0x01)) {
    ungetc(c, stdin); //or bla...
}
模板
类集合与测试{
常数T检验;
T集_u2;;
公众:
SetAndTest(ts=T(),tt=T()):set(s),test(T){
运算符bool(){return set_==test_;}
运算符bool()const{return set_==test_;}
运算符T&({返回集}
运算符T()常量{返回集}
};
//...
如果(自动c=SetAndTest(getc(stdin),0x01)){
ungetc(c,stdin);//或bla。。。
}

如果您担心的是名称空间污染,则始终可以在块中定义
If
语句:

{
    char c = getc(stdin);
    if(c == 0x01)
    {
        // ...
    }
}
这样
c
只会持续到到达块的末尾。

您可以在
if
语句中定义变量。例如,这应编译:

if (int ch = getchar())
    ;
问题是类型(例如,
int
)必须紧跟在左括号之后。额外的括号是导致编译失败的原因。因此,如果你真的想这样做,你需要变得聪明一点,并使用类似这样的东西:

if (char ch = 0 || ((ch = getchar()) == 0x1))

这使您可以完成
ch
的创建和初始化,然后在表达式的该部分完成后,将其放在
ch=getchar()
周围的括号中,以覆盖赋值与比较的优先级

请注意,
&&
|
执行短路评估,因此需要小心初始化。您可以使用:

if (char ch = 0 || ...
…或:

if (char ch = 1 && ...
…但如果尝试使用
if(ch=1 | |…
if(ch=0&&…
),短路求值将使正确的操作数(您真正关心的部分)根本无法求值

现在需要注意的是:虽然我可以合理地确定这段代码符合标准的要求,而且大多数(所有?)当前的编译器都会接受它,但这很可能会导致大多数程序员在阅读代码时感到非常头疼,弄不清您做了什么,以及为什么要这样做。我对在实际代码中使用这一“技术”极为犹豫(充其量)


编辑:有人指出,这样做的结果可能比一些人最初预期的更具误导性,因此我将尝试澄清这种情况。发生的情况是从输入中读取一个值。该值被分配给
ch
,并与
0x1
进行比较。到目前为止,比较结果很好。之后,比较的结果(转换为整数,因此
0
1
)将被分配到
ch
。我相信它有足够的序列点,结果是定义的行为。但它可能不是你或任何人想要的——因此,建议你可能不想使用它,并且提到它可能会让大多数程序员挠头,想知道你在尝试什么确实。在与0x1比较的非常具体的情况下,
if
语句中
ch
的值将是
1
,但这或多或少是一种巧合。如果与0x2比较,
if
ch
的值仍然是
1
,而不是
2
,您可能会滥用
循环。如果它是关于污染的,你总是可以使用一个新的作用域,或者for循环。最简洁(愚蠢)的解决方案可能是
If(int c=getc(stdin)-1);else ungetc(c+1);
。为什么不取消变量定义和初始化的限制?@GManNickG Fung shui?哇,从没想过。你为什么要重复运算符重载?你不能也使用逗号吗?@sje397:如果你尝试使用逗号,我所有的编译器都会拒绝代码(我相信标准要求他们这样做)。@JerryCoffin-1,不管你在其中放入多少个参数,布尔值总是会在
ch
中结束,即
char ch=0 | |((ch=getchar())=42)
将永远不会在if语句的主体中包含
ch==42
。@JerryCoffin当然,但是您还应该提到,您所做的操作相当于
if(getchar()==0x1){/*只需在此处使用'true'而不是ch*/}
“这让您完成ch的创建和初始化,然后[…]”实际上,
|
的右侧仍然是初始化表达式的一部分
if (char ch = 1 && ...