为什么在 if 语句中声明的变量仍在 else 块的范围内?

Why is variable declared in an if-statement still in scope in else block?

考虑这段代码:

if (int* p = nullptr) {
}
else {
    std::cout << *p << std::endl;
}

使用 clang 7.0.1 使用 -std=c++17-Wall-Wextra-pedantic-errors 编译,没有生成任何警告。

我有两个问题:

  1. 这怎么可能?我一直认为这些变量的范围以 if 块结束。如果可能的话,我会感谢标准的报价。

  2. 如果它是合法的,它不应该至少产生一个警告吗?这个功能有什么合理的应用吗?

Why is variable declared in an if-statement still in scope in else block?

因为标准是这样说的。这么设计大概是因为有用吧

  1. How is this possible?

不清楚为什么不可能。

I always thought that scope of such variables ends with the if-block.

你假设错误。

I'd be thankful for quotation from the standard if possible. [language-lawyer]

最新草稿说:

[stmt.select.general]

Selection statements choose one of several flows of control. selection-statement:

  • ...
  • if constexpropt ( init-statementopt condition ) statement else statement
  • ...

请注意,整个 if (condition) statement else statement 是一个选择语句。

[basic.scope.block]

Each

  • selection or iteration statement ([stmt.select], [stmt.iter]),
  • ...

introduces a block scope that includes that statement or handler.

请注意,条件 直接在 if 语句中而不是在子语句中,因此其中的声明会延伸到整个块范围的末尾,其中包含 if 子语句和 else 子语句(这些子语句不是标准名称)。

还有一个非常清楚的例子演示了格式错误的重新声明,并顺便显示了此类声明的范围:

if (int x = f()) {
  int x;            // error: redeclaration of x
}
else {
  int x;            // error: redeclaration of x
}

  1. If it's legal though, shouldn't it at least generate a warning?

是的,如果编译器能够在编译时检测到所有可证明的空指针间接寻址,那就太好了。可能值得提交有关此极端情况的功能请求。

Are there any reasonable applications of such feature?

当然可以。以下捏造的例子对我来说似乎是合理的:

if (Response r = do_request()) {
    log << "great success. content: " << r.content;
} else {
    log << "someone broke it :( error: " << r.error_code;
}

或者如果您不喜欢隐式转换:

if (Response r = do_request(); r.is_success()) {