C++模板定义下用户自定义类型继承编译失败原因及实现方案问询
问题对应C++语义规则
这个报错是C++模板的两阶段查找规则和依赖基类的特性共同导致的:
- 模板分为两个编译阶段:第一阶段是模板定义阶段,此时模板参数还没有被具体类型替换,编译器只会处理非依赖的语法和标识符;第二阶段是模板实例化阶段,模板参数被替换为具体类型后,才会处理所有依赖模板参数的内容。
- 你示例中的
A<T>属于依赖基类(基类类型依赖模板参数T),在模板定义阶段,编译器不会扫描依赖基类的内部成员——因为存在A的特化版本可能删除或修改type成员的可能,此时无法确定type是否存在。 - 你代码中的
type属于非依赖名,编译器会在第一阶段就查找该名称,不会去依赖基类里搜索,因此直接报错未定义。 - 当你继承
A<int>时,基类是不依赖模板参数的非依赖基类,编译器在定义阶段就能确定其内部成员,所以可以正常找到type。
通用解决方案
有符合C++规范的写法可以实现你要的效果,不需要每次都写全基类作用域:
- 方法1:在派生类开头显式引入基类成员(最适合类型别名场景)
直接在派生类中用using声明你需要使用的基类成员,后续就可以直接用短名访问:template <typename T> struct A{ using type = T; }; template <typename T> struct B: A<T>{ using typename A<T>::type; // 显式声明要使用基类的type成员 using type2 = type; // 直接使用即可,编译通过 }; - 方法2:将名称转为依赖表达式(适合成员变量、成员函数场景)
如果是访问基类的成员变量或函数,可以加this->前缀,将标识符转为依赖表达式,查找就会推迟到实例化阶段,自然能找到基类成员。
元编程场景适配
针对你给出的指令集元编程示例,只需要在派生类开头引入所有需要的基类类型别名即可,同时注意访问依赖类型的嵌套类型时需要加typename关键字告知编译器这是一个类型:
template <typename t> struct right_code: public instruction<t>{ // 引入基类成员 using typename instruction<t>::mem; using typename instruction<t>::input; using typename instruction<t>::result; using newmem = buffer<cons<typename mem::list2::head, mem::list1>, (std::is_same<typename mem::list2::tail , nil> ? cons<zero, nil> : typename mem::list2::tail)>; }; template <typename t> using right = typename right_code<t>::result; template <typename t> struct left_code:instruction<t>{ // 引入基类成员 using typename instruction<t>::mem; using typename instruction<t>::input; using typename instruction<t>::result; using newmem = std::conditional_t<std::is_same_v<typename mem::list1::tail, nil>, mem, buffer<typename mem::list1::tail, cons<typename mem::list1::head, typename mem::list2>>>; }; template <typename t> using left = typename left_code<t>::result;
内容的提问来源于stack exchange,提问作者Berindei
相关产品推荐
相关产品推荐

