如何验证两个嵌套变体共享相同类型

问题描述 投票:0回答:1

代码使用嵌套的

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);
}

c++ templates c++20 variadic-templates variant
1个回答
0
投票

如果您预计

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)

© www.soinside.com 2019 - 2024. All rights reserved.