80

我很震惊,这是允许的:

if( int* x = new int( 20 ) )
{
    std::cout << *x << "!\n";
    // delete x;
}
else
{
    std::cout << *x << "!!!\n";
    // delete x;
}
// std:cout << *x; // error - x is not defined in this scope

那么,这是标准允许的还是只是编译器扩展?


PS 由于对此有几条评论 - 请忽略这个例子是“坏的”或危险的。我知道什么。这只是我想到的第一件事,例如。

4

5 回答 5

84

这是规范允许的,因为 C++98。

来自第 6.4 节“选择语句”:

由条件中的声明引入的名称(由类型说明符序列或条件的声明符引入)的范围从其声明点到由条件控制的子语句结束。

以下示例来自同一部分:

if (int x = f()) {
    int x;    // ill-formed, redeclaration of x
}
else {
    int x;    // ill-formed, redeclaration of x
}
于 2012-09-29T18:28:45.753 回答
20

不是真正的答案(但注释不太适合代码示例),更多的是它非常方便的原因:

if (int* x = f()) {
    std::cout << *x << "\n";
}

每当 API 返回一个“选项”类型(它也恰好有一个可用的布尔转换)时,可以利用这种类型的构造,以便该变量只能在可以使用其值的上下文中访问。这是一个非常强大的成语。

于 2012-09-29T19:39:38.620 回答
18

它是标准的,即使在旧的 C++ 98 版本的语言中也是如此:

在此处输入图像描述

于 2012-09-29T18:28:28.593 回答
7

while在 a 、ifswitch语句的条件部分定义变量是标准的。相关条款是 6.4 [stmt.select] 第 1 段,它定义了条件的语法。

顺便说一句,您的使用毫无意义:如果new失败,则会引发std::bad_alloc异常。

于 2012-09-29T18:27:22.370 回答
2

这是一个示例,演示了在if条件中声明的变量的非典型用法。

变量的类型int &既可以转换为布尔值,也可以在thenelse分支中使用。

#include <string>
#include <map>
#include <vector>
using namespace std;

vector<string> names {"john", "john", "jack", "john", "jack"};
names.push_back("bill"); // without this push_back, my g++ generated exe fails :-(
map<string, int> ages;
int babies = 0;
for (const auto & name : names) {
    if (int & age = ages[name]) {
        cout << name << " is already " << age++ << " year-old" << endl;
    } else {
        cout << name << " was just born as baby #" << ++babies << endl;
        ++age;
    }
}

输出是

john was just born as baby #1
john is already 1 year-old
jack was just born as baby #2
john is already 2 year-old
jack is already 1 year-old
bill was just born as baby #3

不幸的是,条件中的变量只能用'='声明语法来声明。

这排除了具有显式构造函数的其他可能有用的类型案例。

例如,下一个使用 an 的示例std::ifstream不会编译...

if (std::ifstream is ("c:/tmp/input1.txt")) { // won't compile!
    std::cout << "true: " << is.rdbuf();
} else {
    is.open("c:/tmp/input2.txt");
    std::cout << "false: " << is.rdbuf();
}

2019 年 1 月编辑...您现在可以效仿我解释的无法完成的事情...

这适用于 C++11 中的 ifstream 等可移动类,甚至适用于自 C++17 以来具有复制省略的不可复制类。

2019 年 5 月编辑:使用 auto 来减轻冗长

{
    if (auto is = std::ifstream ("missing.txt")) { // ok now !
        std::cout << "true: " << is.rdbuf();
    } else {
        is.open("main.cpp");
        std::cout << "false: " << is.rdbuf();
    }
}
struct NoCpy {
    int i;
    int j;
    NoCpy(int ii = 0, int jj = 0) : i (ii), j (jj) {}
    NoCpy(NoCpy&) = delete;
    NoCpy(NoCpy&&) = delete;
    operator bool() const {return i == j;}
    friend std::ostream & operator << (std::ostream & os, const NoCpy & x) {
        return os << "(" << x.i << ", " << x.j << ")";
    }
};
{
    auto x = NoCpy(); // ok compiles
    // auto y = x; // does not compile
    if (auto nocpy = NoCpy (7, 8)) {
        std::cout << "true: " << nocpy << std::endl;
    } else {
        std::cout << "false: " << nocpy << std::endl;
    }
}
于 2013-04-17T02:30:27.643 回答