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

How is a type that's forward declared in a function parameter list visible outside the function scope?

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

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

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

basic.scope.param seems the obvious place I would find this rule, but I can't work it out. The wording could be somewhere in dcl.dcl,但我不确定去哪里找。

这是什么规则?可选地,解释 为什么 这条规则存在会很好。

class s 是前向声明。那相当于

class s;
void f(s);

s 不是变量的名称,而是一种类型。所以你只是说函数 f 接受类型 s 的参数。 下一行也说明 u 等同于 s。没问题。你不需要完整的定义来做到这一点。

首先,这条规则并不是特别新。它几乎从 C++ 诞生之初就存在了。至于C++20,是这样写的:

[basic.scope.pdecl]

7 The point of declaration of a class first declared in an elaborated-type-specifier is as follows:

  • ...
  • for an elaborated-type-specifier of the form
    class-key identifier
    
    if the elaborated-type-specifier is used in the decl-specifier-seq or parameter-declaration-clause of a function defined in namespace scope, the identifier is declared as a class-name in the namespace that contains the declaration; otherwise, except as a friend declaration, the identifier is declared in the smallest namespace or block scope that contains the declaration.

但你正在寻找最新的最伟大的草稿头。您找不到它,因为草案已 P1787 合并。它更改了规范性措辞并移动它,目的是修复一些突出的措辞问题并改进标准在模块存在的世界中的方法。

今天相关部分在

[dcl.type.elab]

3 Otherwise, an elaborated-type-specifier E shall not have an attribute-specifier-seq. If E contains an identifier but no nested-name-specifier and (unqualified) lookup for the identifier finds nothing, E shall not be introduced by the enum keyword and declares the identifier as a class-name. The target scope of E is the nearest enclosing namespace or block scope.

从本质上讲,它与 C++20 措辞的含义相同。它将 class 名称引入最近的封闭范围,就好像通过前向声明一样。


至于为什么会有这条规定。好吧......它在最新的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, which frankly don't seem justified. IMHO it's a shortcoming of C, which in turn is motivation enough for C++ to do things the way it does. Compile the exact same program with a C++ compiler, and it's well formed