为何无法在非封闭作用域中定义C++类或函数?
请考虑以下代码:
namespace M { void f(); struct S; } namespace N { void M::f() {} struct M::S {}; }
我测试过的所有编译器均拒绝这段代码,原因是M::f和M::S仅允许在封闭作用域中定义。C++标准中也有示例暗示函数只能在封闭作用域中定义。
但我无法在标准中找到对应的具体规则。C++20标准的[class.pre]/3条款规定:
如果类头名包含嵌套名称说明符,类说明符必须引用一个此前直接在嵌套名称说明符所指向的类或命名空间中声明的类,或是该命名空间的内联命名空间集合中的元素(即不能仅通过继承或
using声明引入),且类说明符必须出现在包含此前声明的命名空间中。这种情况下,定义的类头名的嵌套名称说明符不能以decltype说明符开头。
针对成员函数也有相关规则,但我未找到针对自由函数的规则。P1787R6移除了上述措辞,但替代措辞似乎未包含相同限制。以下是C++23草案中[class.pre]的内容:
如果类头名包含嵌套名称说明符,类说明符不能处于类作用域中。如果其类名是标识符,类说明符必须对应一个或多个可在嵌套名称说明符指向的类、类模板或命名空间中提名的声明;这些声明必须具有相同的目标作用域,且类说明符的目标作用域就是该作用域。[...]
在上述示例中,尝试定义M::S时使用的嵌套名称说明符 M::表示命名空间M,且S此时在M中是可提名的,因为S已在M中预先声明;参见[basic.scope.scope]/6。
由于在C++23草案中找不到禁止在非封闭作用域中定义的规则,我可能会认为P1787R6已允许该操作。但由于编译器仍不接受这段代码,我更倾向于认为该规则仍然存在,只是我未找到(或措辞比之前更隐晦)。
内容的提问来源于stack exchange,提问作者Brian Bi

