C++11下派生类引用基类别名模板第四种写法编译失败求解
C++派生类继承基类别名模板编译失败问题分析
问题现象
在基于基类的别名模板声明派生类同名别名模板时,前3种写法可正常编译,第4种偏好写法在gcc 4.8.3、std=c++11编译环境下编译失败。
设计别名模板的目的是在复杂实现场景下代入分配器参数时更加易用:DummyAllocator是DummyContainer的分配器实现,Base和Derived两个类分别实例化了模板参数为int和double的DummyContainer对象。
编译报错信息
g++ -Wall -pedantic -std=c++11 main.cpp -o out main.cpp:43:31: error: expected type-specifier using ContainerType = BaseClass::ContainerType<T>; ^ main.cpp:46:9: error: ‘ContainerType’ does not name a type ContainerType<double> double_container;
相关测试代码
template <typename T> class DummyAllocator { public: static T dummy_allocate() { return (T)0; } }; template <typename T, typename _Allocator = DummyAllocator<T> > class DummyContainer { public: DummyContainer() { _Allocator::dummy_allocate(); } }; template <typename _Allocator> class Base { public: template <typename T> using ContainerType = DummyContainer<T, _Allocator>; private: ContainerType<int> int_container; }; template <typename _Allocator> class Derived : public Base<_Allocator> { public: // (1) 该写法可正常编译 //template <typename T> //using ContainerType = DummyContainer<T, _Allocator>; // (2) 该写法可正常编译 //template <typename T> //using ContainerType = Base<_Allocator>::ContainerType<T>; // (3) 该写法可正常编译 //typedef _Allocator Allocator; //template <typename T> //using ContainerType = Base<Allocator>::ContainerType<T>; // (4) 该写法编译失败 using BaseClass = Base<_Allocator>; template <typename T> using ContainerType = BaseClass::ContainerType<T>; private: ContainerType<double> double_container; }; int main(int, const char**) { Base<DummyAllocator<int> > base; Derived<DummyAllocator<int> > derived; return 0; }
失败原因分析
BaseClass是Base<_Allocator>的别名,而_Allocator是Derived类的模板参数,因此BaseClass属于依赖型类型(依赖外部模板参数才能确定具体类型)。
C++标准规定:访问依赖型类型作用域内的嵌套模板时,必须显式添加template关键字告知编译器该标识符是模板,否则编译器会默认将后续的<解析为小于运算符,引发语法解析错误。同时需要添加typename关键字告知编译器BaseClass::ContainerType是一个类型名称,而非静态成员或其他符号。
前3种写法能编译通过,本质是gcc 4.8.3版本的非标准兼容行为,按照C++11标准,这3种写法也需要添加typename和template关键字才能保证跨编译器兼容性。
解决方案
修改第4种写法,补充typename和template关键字即可:
using BaseClass = Base<_Allocator>; template <typename T> using ContainerType = typename BaseClass::template ContainerType<T>;
修改后即可在gcc 4.8.3 C11环境下正常编译,同时符合C标准要求,可兼容其他编译器及更高版本的gcc。
内容的提问来源于stack exchange,提问作者pyrate
相关产品推荐
相关产品推荐

