C++中能否定义与父模板类同名的别名?Clang和GCC谁符合标准?
问题示例
如下代码中,Derived<T> 结构体继承自 Base<T>,并定义了名为 Base 的别名指向父类:
template <class T> struct Base { Base(int) {} }; template <class T> struct Derived : Base<T> { using Base = Base<T>; Derived() : Base(1) {} }; int main() { Derived<char> x; }
Clang 支持这段代码编译通过,而 GCC 会抛出编译错误:
error: declaration of 'using Base = struct Base<T>' changes meaning of 'Base' [-fpermissive]
结论
GCC 的行为严格符合 C++ 标准要求,Clang 属于非标准的规则放宽。
规则说明
C++ 标准明确要求:类作用域中使用的任意名称,在其使用时的上下文、以及类完整作用域下重新解析时,必须指向同一个声明。
在本示例中:
- 派生类基类列表中的
Base<T>使用未限定名Base时,查找结果是全局作用域下的类模板Base - 后续派生类体内的
using Base = Base<T>,会把派生类作用域内的Base重新绑定为Base<T>的类型别名 - 同一个
Base名称在派生类的不同位置指向了完全不同的实体(前者是模板,后者是类型),已经违反了上述标准规则。
标准允许编译器对这类违规选择是否输出诊断信息,因此 Clang 不报错属于允许的实现差异,但 GCC 的错误提示是完全符合标准的处理方式。
兼容提示:如果要让代码同时在两个编译器编译通过,可以将别名声明修改为
using Base = ::Base<T>;,显式指定从全局作用域查找Base模板,即可规避名称含义变更的问题。
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

