C++中局部类的友元函数能否在命名空间作用域定义?
局部类友元函数的标准合规性分析
局部类友元函数的定义限制
C++中局部类可以拥有友元函数,但存在两个明确的标准限制:
- 不能在类内部定义,出自标准[class.friend] p5:
A function may be defined in a friend declaration of a class if and only if the class is a non-local class and the function name is unqualified.
- 也不能在所属函数内部定义,出自标准[dcl.fct.def.general] p2:
[...] A function shall be defined only in namespace or class scope. [...]
全局作用域定义局部类友元的代码示例
有人尝试将局部类的友元函数放在全局作用域定义,代码如下:
auto foo() { struct A; void bar(const A&); struct A { friend void bar(const A&); }; bar(A{}); return A{}; } using A = decltype(foo()); void bar(const A&) {} int main() { foo(); }
各编译器的处理差异
- MSVC:编译时给出警告,链接阶段失败:
warning C5046: 'bar': Symbol involving type with internal linkage not defined error LNK2019: unresolved external symbol "void __cdecl bar(struct `__cdecl foo(void)'::`2'::A const &)" (?bar@@YAXAEBUA@?1??foo@@YA@XZ@@Z) referenced in function "__cdecl foo(void)" (?foo@@YA@XZ) - EDG:直接报编译错误:
error: function "bar", declared using a local type, must be defined in this translation unit - GCC:仅在添加
-fpermissive标志时接受程序,同时输出警告:warning: 'void bar(const foo()::A&)', declared using local type 'const foo()::A', is used but never defined [-fpermissive] - Clang:可以无警告正常编译该程序。
标准合规性判断
要明确哪种实现符合标准,核心在于局部类型的链接属性和函数声明与定义的匹配规则:
- 局部类
foo()::A属于具有内部链接的类型,根据C++标准,使用内部链接类型作为参数的函数,其声明和定义必须满足:该函数的定义必须与声明处于同一个翻译单元,且要保证参数类型的同一性。 - 此处的矛盾点在于:
foo()内部声明的bar(const A&)中的A是仅在foo()作用域内可见的局部类,而全局作用域的void bar(const A&)中的A是decltype(foo())的别名——但内部链接属性限定了foo()::A无法在全局作用域被正确引用,导致两个bar的参数类型本质上不匹配,全局的bar无法对应foo()内部声明的友元函数。
综上,EDG和GCC的行为更符合C++标准:EDG直接在编译阶段拦截错误,GCC在默认模式下拒绝编译,仅在放宽限制的-fpermissive模式下给出警告;Clang的处理属于对标准的放宽;MSVC的链接错误则是因为无法找到匹配的函数符号,本质上也是符合标准逻辑的结果。
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

