从模板using别名继承时为何需指定完整模板参数才能使用父类构造函数?
从模板using别名继承时为何需指定完整模板参数才能使用父类构造函数?
这个问题其实戳中了C++里using别名模板和类模板一个容易混淆的细节——它们看起来功能类似,但编译器对二者的处理逻辑可是有本质区别的!先把你给出的代码贴出来方便大家对照:
template<typename T> class A {}; template<typename T> using B = A<T>; class DerivedA: public A<int> { using A::A; // 正常工作 }; class DerivedB: public B<int> { using B::B; // 报错:"Use of alias template 'B' requires template arguments" // using B<int>::B; // 这样写就正常了 };
下面给你掰扯清楚背后的原因:
先看
DerivedA的情况:直接用类模板实例的注入类名
当DerivedA继承A<int>时,A<int>是类模板A实例化后的具体类,不是模板本身。在子类DerivedA里写using A::A;时,这里的第一个A是基类A<int>的注入类名——简单说就是编译器自动把基类的类名“注入”到了子类的作用域里,这个A直接指代A<int>这个具体类,所以编译器能直接找到它的构造函数,不需要额外指定模板参数。再看
DerivedB的坑:别名模板不是具体类型B是一个别名模板,它本质上就是“类模板A的快捷方式”,但它本身不是具体类型,只有当你给它传模板参数(比如B<int>)时,它才会指向具体的A<int>类型。
当你在DerivedB里写using B::B;时,编译器会把第一个B识别成别名模板本身,而不是已经实例化的B<int>类型。既然是模板,编译器自然会要求你提供模板参数,这就出现了报错。为什么
using B<int>::B;就正常?
因为B<int>是别名模板B实例化后的具体类型(也就是A<int>),这时候编译器能明确找到对应的基类类型,进而找到它的构造函数,所以就不会报错了。
总结一下:别名模板是“模板的别名”,不是类型;类模板实例化后是具体类型,它的注入类名可以在子类里直接复用。所以用别名模板的名字调用构造函数时,必须明确指定实例化参数,让编译器知道你指的是哪个具体类型的构造函数。




