代码之家  ›  专栏  ›  技术社区  ›  cigien Jorge Eldis

在函数参数列表中正向声明的类型如何在函数范围外可见?

  •  3
  • cigien Jorge Eldis  · 技术社区  · 5 年前

    下面的程序编译,我觉得很奇怪。

    void f(class s);
    using u = s;      // ok, but why?
    

    s 是函数参数列表中类的前向声明,在我看来,它不应该在函数范围之外可见。

    basic.scope.param 似乎是一个显而易见的地方,我会找到这个规则,但我无法解决它。措辞可能在某个地方 dcl.dcl ,但我不知道该去哪里找。

    这是什么规定?或者,解释 为什么? 如果有这个规则就好了。

    1 回复  |  直到 5 年前
        1
  •  4
  •   StoryTeller - Unslander Monica    5 年前

    首先,这条规则并不特别新。它几乎是从C++诞生以来就存在的。对于C++20,其编写如下:

    [basic.scope.pdecl]

    7 首先在详细的类型说明符中声明的类的声明要点如下:

    • ...
    • 对于表单的详细类型说明符
      class-key identifier
      
      如果在命名空间作用域中定义的函数的decl说明符seq或参数声明子句中使用了详细的类型说明符,则该标识符将在包含该声明的命名空间中声明为类名;否则,除了作为友元声明之外,标识符将在包含该声明的最小命名空间或块范围中声明。

    但你要看的是最新最棒的选秀节目。你找不到,因为草稿上写着 P1787 融入其中。它改变了规范性措辞,并将其移动,旨在解决一些悬而未决的措辞问题,并在存在模块的世界中改进标准的方法。

    今天,相关部分位于

    [dcl.type.elab]

    3 否则,详细的类型说明符E不应具有属性说明符seq。如果E包含一个标识符,但没有嵌套的名称说明符,并且(非限定的)标识符查找没有发现任何内容,则E不应由enum关键字引入,并将标识符声明为类名。E的目标范围是最近的封闭命名空间或块范围。

    从本质上讲,它的意思与C++20的措辞相同。它将类名引入到最近的封闭范围中,就像通过转发声明一样。


    至于这个规则为什么存在。好到目前为止,它在C语言中还不存在。这给新手带来了一些相当模糊的问题。考虑这个简单的程序:

    void func(struct foo*);
    
    struct foo { int bar; };
    
    int main() {
      struct foo f;
      func(&f);
    }
    
    void func(struct foo* pf) {
      pf->bar = 0;
    }
    

    它产生一个 slew of diagnostics 坦白说,这似乎不合理。IHO是C的缺点,这又足以激励C++以它的方式做事。用C++编译器编译完全相同的程序,并且它是 well formed .

        2
  •  0
  •   Costantino Grana    5 年前

    class s 这是一项前瞻性声明。这相当于

    class s;
    void f(s);
    

    s 不是变量的名称,但它是一种类型。所以你只是在说这个函数 f 接受类型为的参数 s . 下一行也告诉我们 u 相当于 s .没问题。你不需要完整的定义就能做到这一点。

    推荐文章