【问题标题】:Scope of variable declared in condition在条件中声明的变量范围
【发布时间】:2013-08-14 07:33:38
【问题描述】:

一些重构导致了一段代码,使我得到了这个最小的测试用例:

int main () {
    if (int i=1) {
        /* IF-BLOCK */
    } else {
        throw i;
    }
}

这编译得很好。但是,我一直认为i 只对IF-BLOCK 可见,但似乎并非如此。这是编译器错误吗?

另外,为什么以下工作?

int main () {
    if (int i=1) {
    } else if (int i=2) {
    } else {
        throw i;
    }
}

注意第二个if“重新声明”i。另一个编译器错误?

【问题讨论】:

  • 这是 C++ 中一个非常有用的特性。我认为人们想到的主要用例是if (auto p = dynamic_cast<Foo*>(q)) { /* ... use p ... */ } 之类的东西,或者任何一种创建可能为空的指针的情况。

标签: c++ scope


【解决方案1】:

不,这实际上是正确的行为。

6.4 选择语句 [stmt.select]

由条件中的声明引入的名称(由 type-specifier-seq 或条件的声明符引入)从其声明点到子语句控制 由条件。 如果在子语句的最外层块中重新声明了名称 条件,重新声明名称的声明格式错误的。 [示例:

if (int x = f()) {
    int x; // ill-formed, redeclaration of x
}
else {
    int x; // ill-formed, redeclaration of x
}

—结束示例]

(强调我的)

这基本上意味着i的范围从条件开始,在if-block之后结束,其中else-block也是if-block的一部分。

嵌套if 的第二个问题是基于(错误的)假设,即else-if 是介绍性if 的一部分,但事实并非如此。 if (int i=2)第一个 else 的主体

     if (int i=1)
          |
         / \
        /   \
       /     \
      /       \
     /         \
   if-block   else
               |
           if(int i=2)
             /    \
            /      \
           /        \
       if-block   throw i

这又意味着什么:

int main () {
    if (int i=1) {    
    } else if (1) {
        throw (i+2);
    } else {
        throw i;
    }
}

此代码有效,因为i 声明在throw (i+2); 中可见,但隐藏第一个i 仍然有效,因为在嵌套作用域中,名称可以被覆盖:

int main () {
    if (int i=1) {    
    } else if (int i=2) {
        throw (i+2); // now refers to `int i=2`
    } else {
        throw i;
    }
}

总而言之,不要惊慌:使用最后一条语句中找到的模式编写标记器或解析器或其他东西仍然有效,这里的相关新知识是条件中的任何声明跨越整个if-tree , 但可以在任何嵌套的 if 中被覆盖。

另外,请确保以下内容仍然无效(即使它在旧编译器中有效):

if (int i=0) {}
std::cout << i; // nope, not valid

【讨论】:

  • +1 从未想过这一点,很高兴知道。这背后有什么故事吗,还是你只是想分享你因为学术兴趣挖出来的东西?
  • @Hulk:我在重构一些爱好代码时挖掘了它,在开车去我真正的工作场所之前,即使我删除了它的声明,变量仍然可以访问:)。你可以在那里看到实际的变化:github.com/phresnel/excygen/commit/…。最初,只有if (auto oit = operator_(it, end)),然后我用if (*it == '/')之类的东西删除了它,但在它的块内,它仍然访问oit,它编译了,但我得到了一个单元化optional&lt;&gt;的例外,这一切都是我发现并想分享的内容:)
猜你喜欢
  • 1970-01-01
  • 2020-03-18
  • 2014-09-20
  • 2013-11-19
  • 1970-01-01
  • 1970-01-01
  • 2012-06-28
  • 1970-01-01
相关资源
最近更新 更多