嵌套模板场景下如何暴露继承的构造函数?
问题分析与解决方案
问题重现
首先看可正常编译的非模板版本:
#include <string> #include <variant> class my_variant : public std::variant<int, std::string> { using variant::variant; public: std::string foo() { return "foo"; } };
当将基类改为依赖模板参数的特化版本时,编译报错:
template <typename TChr> class my_variant : public std::variant<int, std::basic_string<TChr>> { // 编译错误:'variant': is not a class or namespace name using variant::variant; public: std::basic_string<TChr> foo() { return "foo"; } };
用户尝试显式指定模板参数但未加命名空间限定,依然报错:
template <typename TChr> class my_variant : public std::variant<int, std::basic_string<TChr>> { // 同样报错 using variant<int, std::basic_string<TChr>>::variant; public: std::basic_string<TChr> foo() { return ""; } };
解决方案
方案1:显式添加std::命名空间限定
#include <string> #include <variant> template <typename TChr> class my_variant : public std::variant<int, std::basic_string<TChr>> { // 显式指定std::命名空间下的variant特化 using std::variant<int, std::basic_string<TChr>>::variant; public: std::basic_string<TChr> foo() { return "foo"; } };
方案2:先定义基类别名,再引用构造函数
这种写法更简洁,尤其是基类类型较长时:
#include <string> #include <variant> template <typename TChr> class my_variant : public std::variant<int, std::basic_string<TChr>> { private: // 定义基类别名 using Base = std::variant<int, std::basic_string<TChr>>; public: // 通过别名引用基类构造函数 using Base::Base; std::basic_string<TChr> foo() { return "foo"; } };
原因解释
在模板类中,当基类是依赖于模板参数的类型(即依赖类型)时,编译器在解析模板的阶段(实例化之前)无法确定variant这个名字的来源:它既可能是std::variant,也可能是当前作用域的其他实体。此时必须通过显式的命名空间限定(std::),或者通过预先定义的基类别名,来明确告诉编译器要引用的基类构造函数所属的类型。
非模板版本中,基类是明确的std::variant<int, std::string>,编译器可以通过当前类的基类作用域找到variant,但模板版本中基类依赖模板参数TChr,必须显式限定作用域才能让编译器正确识别。
内容的提问来源于stack exchange,提问作者Regus Pregus
相关产品推荐
相关产品推荐

