代码使用嵌套的
std::variant
来建模消息:
class A{};
class B{};
class C{};
class D{};
using CMD1 = std::variant<A, B>;
using CMD2 = std::variant<C, D>;
using CMD = std::variant<cmd1, cmd2>;
为了将消息发送给正确的参与者,参与者定义了一个公共
typelist
,其中包含他们想要接收的所有命令类型:
struct ActorAC {
using handleable = typelist<A,C>;
};
struct ActorBD {
using handleable = typelist<B, D>;
};
在运行时,调度程序接收一个命令 - 类型是封装所有其他子变体的变体,然后它检查命令的 concrete 类型是否在 actor 的
typelist
内部,如果是,则将消息发送到演员:
CMD cmd = get_cmd();
//this is what I'd like to do
if (is_any(get_concrete_type(cmd), actorAC::handleables)){
// send message to actorAC
}
if (is_any(get_concrete_type(cmd), actorBD::handleables)) {
//send message to actor BD
}
获取变体的当前成员只能使用
visit
,所以让我们尝试一下,我们将编写一个函数来检查给定类型是否是变体的具体类型之一:
template <typename HandlableType, typename... Types>
constexpr bool is_concrete(std::variant<Types...> v) {
return std::visit(Overload{
[](HandelableType) {
/*it's the same Type! finished*/
return true;
},
[]<typename... Typesin>(std::variant<Typesin...> vin) {
/* we still didn't get to the leaf variants*/
return is_in_concrete<HandlableType>(vin);
},
[](auto) {
/* if it is not a variant and also not our type - for sure it's not what we want*/
return false;
},
},
v);
}
让我们尝试使用它:
int main(){
CMD cmd(A());
//should compile and return true
return is_concrete<A>(cmd);
}
但我从 g++-13 收到此错误:
错误:没有匹配的函数来调用“is_concrete”
注意:候选模板被忽略:无法将 'std::variant
' 与 'std::variant ()(A)' 匹配(又名 'variant ,variant )(A)')> (
因此,在
main
第一次调用时,编译器不匹配 - 发生了什么??
理想的最终结果是:
template<typename... tl>
bool shouldActUpon(CMD cmd) {
return (is_concrete<tl>(cmd) || ...);
}
这是完整的文件:
#include <variant>
template <typename... Ts> struct Overload : Ts... {
using Ts::operator()...;
};
template <typename... Ts> Overload(Ts...) -> Overload<Ts...>;
class A {};
class B {};
class C {};
class D {};
using V1 = std::variant<A, B>;
using V2 = std::variant<C, D>;
using V = std::variant<V1, V2>;
template <typename HandlableType, typename... Types>
constexpr bool is_concrete(std::variant<Types...> cmd) {
return std::visit(Overload{
[&](HandlableType) {
/*v1 is a variant in the index call recursive*/
return true;
},
[&]<typename... Typesin>(std::variant<Typesin...> vin) {
return is_concrete<HandlableType>(vin);
},
[](auto) {
/*v1 is not a variant - both are of the same type,
* same index, and leaf*/
return true;
},
},
cmd);
}
int main() {
V cmd(A);
is_concrete<A>(cmd);
}
如果您预计
main
返回 1,请尝试将 V cmd(A);
更改为 V cmd{A{}};
。
确实,如果你仔细查看错误,
note: candidate template ignored: could not match
'std::variant<Types...>'
against
'std::variant<V1, V2> (*)(A)' (aka 'variant<variant<A, B>, variant<C, D>> (*)(A)')
它告诉您编译器无法将变体与... 指向参数类型为
A
的函数的指针并返回变体值。
所以你应该想知道“为什么编译器认为我正在传递指向函数的指针”??
好吧,MVP 就是答案:
V cmd(A);
是一个名为 cmd
的函数的声明,其参数类型为 A
,返回类型为 V
,其类型为 V(A)
;当作为参数传递时,该类型会衰减为指向 函数等的指针,即 V(*)(A)
。