C++23中decltype能否指定类方法所属类?编译器分歧解析
当使用-std=c++23编译选项时,GCC可正常编译以下代码,但Clang 18.1会报错:
struct outer { struct { int x; inline int get_x() const; } inner; }; inline int decltype(outer::inner)::get_x() const { return x; }
Clang的错误信息如下:
nested.cc:9:25: error: 'decltype' cannot be used to name a declaration
9 | decltype(outer::inner)::get_x() const
| ~~~~~~~~~~~~~~~~~~~~~~ ^
两款编译器均接受通过类型别名中转的写法:
using inner_type = decltype(outer::inner); inline int inner_type::get_x() const { return x; }
1. 哪款编译器符合C++23标准?原因是什么?
GCC的行为符合C++23标准。
C23删除了C20及更早版本中[class.mfct]条款对非局部类成员函数定义的嵌套名称说明符的限制。根据C++23标准的[expr.prim.id.dtor]和[basic.lookup.qual]相关规则,decltype(outer::inner)可作为嵌套名称说明符的一部分,直接指代匿名结构体类型,进而定义其外联成员函数。
Clang的报错源于尚未完全实现C++23的这一规则更新,仍沿用旧标准中禁止用decltype直接作为嵌套名称说明符来命名类类型进行成员定义的限制。
2. 避免使用类型别名定义匿名结构体外联成员函数的技巧
在支持C++23标准的编译器(如GCC)中,直接使用decltype(outer::inner)::get_x()的写法就是符合标准的方案,无需类型别名。
如果需要兼容暂未实现该特性的编译器(如当前版本的Clang),可以选择将成员函数直接内联在匿名结构体内部:
struct outer { struct { int x; inline int get_x() const { return x; } } inner; };
3. 内部类型为private时的实现方式
当内部匿名结构体是private成员时,外联定义需要突破访问权限限制,可采用以下两种方式:
- 友元声明配合标准写法:在
outer类中声明外联的get_x定义为友元,使其能访问private的内部类型:struct outer { private: struct { int x; inline int get_x() const; } inner; friend int decltype(inner)::get_x() const; }; inline int decltype(outer::inner)::get_x() const { return x; } - 类型别名+友元:如果需要兼容Clang,可先在
outer内部定义private的类型别名,再声明外联定义为友元:struct outer { private: struct { int x; inline int get_x() const; } inner; using inner_type = decltype(inner); friend int inner_type::get_x() const; }; inline int outer::inner_type::get_x() const { return x; }
内容的提问来源于stack exchange,提问作者user3188445

