首页 > 解决方案 > 在函数参数列表中前向声明的类型如何在函数范围之外可见?

问题描述

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

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

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

basic.scope.param似乎是我可以找到此规则的明显位置,但我无法解决。措辞可能在dcl.dcl中的某个地方,但我不确定在哪里看。

什么规则涵盖了这一点?可选地,解释为什么存在此规则会很好。

标签: c++scopelanguage-lawyerdeclarationfunction-parameter

解决方案


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

[basic.scope.pdecl]

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

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

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

今天,相关部分位于

[dcl.type.elab]

3否则,详细类型说明符 E 不应具有属性说明符序列。如果 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;
}

它产生了大量的诊断,坦率地说,这似乎不合理。恕我直言,这是 C 的一个缺点,而这反过来又是 C++ 以它的方式做事的足够动力。用 C++ 编译器编译完全相同的程序,它的格式很好


推荐阅读