嵌套std::variant类型匹配检查代码编译报错,求排查与解决
嵌套std::variant类型匹配错误分析与运行时检查实现
错误原因分析
你遇到的no matching function for call to 'is_concrete'错误,本质是模板参数推导失败,具体原因有两点:
- 模板签名错误:错误提示里的
std::variant<V1, V2> (*)(A)说明你的is_concrete模板可能错误地将参数声明为函数指针类型,而非直接接收std::variant类型作为模板/函数参数。编译器试图将传入的std::variant对象匹配成函数指针,自然无法匹配。 - variant参数长度不兼容:如果你的模板仅针对二元
std::variant<V1, V2>设计,但实际传入的是变长参数的std::variant<Types...>(比如外层CMD是std::variant<CMD1, CMD2>),模板无法匹配变长参数的variant类型,导致推导失败。
解决方案:实现shouldActUpon函数
要实现运行时检查嵌套variant的具体类型是否属于Actor的可处理列表,需要递归展开所有嵌套的variant,最终检查最内层的具体类型是否在目标类型列表中。以下是完整实现:
1. 基础类型列表检查工具
首先实现一个工具,用于检查单个类型是否存在于指定typelist中:
#include <variant> #include <type_traits> #include <iostream> // 定义typelist结构 template<typename... Ts> struct typelist {}; // 检查类型T是否在Typelist中 template<typename T, typename Typelist> struct is_type_in_list : std::false_type {}; template<typename T, typename Head, typename... Tail> struct is_type_in_list<T, typelist<Head, Tail...>> : std::disjunction<std::is_same<T, Head>, is_type_in_list<T, typelist<Tail...>>> {}; template<typename T, typename Typelist> constexpr bool is_type_in_list_v = is_type_in_list<T, Typelist>::value;
2. 递归展开嵌套variant的检查模板
实现递归模板,自动展开所有嵌套的std::variant,直到找到最内层的具体类型:
// 递归展开variant,检查最内层类型是否在Typelist中 template<typename Variant, typename Typelist> struct is_concrete_in_list : std::false_type {}; // 处理变长参数的variant,递归检查每个成员 template<typename... VariantTypes, typename Typelist> struct is_concrete_in_list<std::variant<VariantTypes...>, Typelist> : std::disjunction<is_concrete_in_list<VariantTypes, Typelist>...> {}; // 终止条件:非variant类型,直接检查是否在列表中 template<typename T, typename Typelist> struct is_concrete_in_list<T, Typelist> : std::bool_constant<is_type_in_list_v<T, Typelist>> {}; template<typename Variant, typename Typelist> constexpr bool is_concrete_in_list_v = is_concrete_in_list<Variant, Typelist>::value;
3. 实现shouldActUpon运行时检查函数
利用std::visit遍历variant的实际存储类型,结合上面的模板完成运行时判断:
template<typename Actor, typename CMD> bool shouldActUpon(const CMD& cmd) { using HandleableList = typename Actor::handleable; return std::visit([](const auto& concrete_cmd) { // 推导当前具体类型,检查是否在可处理列表中 using ConcreteType = std::decay_t<decltype(concrete_cmd)>; return is_concrete_in_list_v<ConcreteType, HandleableList>; }, cmd); }
4. 使用示例
// 定义基础消息类型 struct A {}; struct B {}; struct C {}; struct D {}; // 定义嵌套variant消息 using CMD1 = std::variant<A, B>; using CMD2 = std::variant<C, D>; using CMD = std::variant<CMD1, CMD2>; // 定义Actor,声明可处理的类型列表 struct MyActor { using handleable = typelist<A, C>; // 仅处理A和C类型 }; int main() { CMD cmd_a = CMD1{A{}}; CMD cmd_d = CMD2{D{}}; std::cout << std::boolalpha; std::cout << shouldActUpon<MyActor>(cmd_a) << "\n"; // 输出true std::cout << shouldActUpon<MyActor>(cmd_d) << "\n"; // 输出false return 0; }
内容的提问来源于stack exchange,提问作者Eyal Kamitchi
相关产品推荐
相关产品推荐

