C++派生类中约束参数类型适配std::variant基类的问题求解
问题描述
我定义了一个继承自std::variant的variant2类型,希望提前捕获赋值类型与变体类型不匹配的潜在错误。但当前方案存在问题:内部std::variant的typedef在类闭包前不完整,无法通过concept传递。请问有哪些替代方案?(注:生产代码中assign函数复杂,需提前捕获错误提升用户友好性)
示例代码
#include <concepts> #include <iostream> #include <string> #include <type_traits> #include <variant> template <typename T, typename Variant> struct is_variant_type; template <typename T, template <typename...> typename Var, typename... Args> struct is_variant_type<T, Var<Args...>> : public std::disjunction<std::is_same<T, Args>...> {}; template <typename T, typename Variant> concept variant_type = is_variant_type<T, Variant>::value; template <typename T> struct variant2 : public std::variant<std::monostate, int, T> { using inner_variant_type = variant2::variant; template <variant_type<inner_variant_type> U> auto assign(const U& arg) { *this = arg; } }; int main() { variant2<std::string> var; var.assign(2); }
报错信息
<source>:19:42: error: invalid use of incomplete type 'struct variant2<T>' 19 | using inner_variant_type = variant2::variant; | ^~~~~~~ <source>:18:8: note: definition of 'struct variant2<T>' is not complete until the closing brace 18 | struct variant2 : public std::variant<std::monostate, int, T> { | ^~~~~~~~ <source>:21:28: error: 'inner_variant_type' was not declared in this scope; did you mean 'is_variant_type'? 21 | template <variant_type<inner_variant_type> U> | ^~~~~~~~~~~~~~~~~~ | is_variant_type
解决方案
方案1:直接关联基类类型定义约束
因为variant2继承自固定的std::variant<std::monostate, int, T>,可以直接让concept绑定这个基类类型,避开类内类型不完整的问题:
#include <concepts> #include <iostream> #include <string> #include <type_traits> #include <variant> template <typename T, typename Variant> struct is_variant_type; template <typename T, template <typename...> typename Var, typename... Args> struct is_variant_type<T, Var<Args...>> : public std::disjunction<std::is_same<T, Args>...> {}; // 修改concept,直接关联variant2的基类类型 template <typename U, typename T> concept variant2_type = is_variant_type<U, std::variant<std::monostate, int, T>>::value; template <typename T> struct variant2 : public std::variant<std::monostate, int, T> { template <variant2_type<T> U> auto assign(const U& arg) { *this = arg; } }; int main() { variant2<std::string> var; var.assign(2); // 正常编译 // var.assign(3.14); // 编译报错,double不在类型列表中 }
方案2:用外部模板别名延迟类型引用
通过外部模板别名明确基类类型,避免在类未完成定义时引用自身:
#include <concepts> #include <iostream> #include <string> #include <type_traits> #include <variant> template <typename T, typename Variant> struct is_variant_type; template <typename T, template <typename...> typename Var, typename... Args> struct is_variant_type<T, Var<Args...>> : public std::disjunction<std::is_same<T, Args>...> {}; template <typename T, typename Variant> concept variant_type = is_variant_type<T, Variant>::value; // 外部定义基类类型的模板别名 template <typename T> using variant2_base = std::variant<std::monostate, int, T>; template <typename T> struct variant2 : public variant2_base<T> { template <variant_type<variant2_base<T>> U> auto assign(const U& arg) { *this = arg; } }; int main() { variant2<std::string> var; var.assign(2); // 正常编译 // var.assign("test"); // 编译报错,const char*无法匹配std::string }
方案3:用decltype(*this)延迟完整类型推导
利用decltype在模板实例化时才求值的特性,间接获取完整的variant2类型:
#include <concepts> #include <iostream> #include <string> #include <type_traits> #include <variant> template <typename T, typename Variant> struct is_variant_type; template <typename T, template <typename...> typename Var, typename... Args> struct is_variant_type<T, Var<Args...>> : public std::disjunction<std::is_same<T, Args>...> {}; template <typename T, typename Variant> concept variant_type = is_variant_type<T, Variant>::value; template <typename T> struct variant2 : public std::variant<std::monostate, int, T> { template <typename U> requires variant_type<U, decltype(*this)> auto assign(const U& arg) { *this = arg; } }; int main() { variant2<std::string> var; var.assign(2); // 正常编译 // var.assign(3.14); // 编译报错 }
各方案优缺点
- 方案1:代码最简洁,直接绑定基类类型,适合基类结构固定的场景。
- 方案2:可读性强,基类类型集中管理,后续修改基类时只需调整模板别名。
- 方案3:无需显式引用基类,依赖类型推导,适合基类结构可能变动的场景。
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

