如何验证两个嵌套变体是否共享同一类型

How to verify that two nested variants share the same type

提问人:Eyal Kamitchi 提问时间:9/25/2023 最后编辑:康桓瑋Eyal Kamitchi 更新时间:9/25/2023 访问量:62

问:

该代码使用嵌套的 s 对消息进行建模: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>;
};

在运行时,调度程序接收到一个命令 - 类型是封装所有其他子变体的变体,然后它检查命令的具体类型是否在 actor 的 中,如果是,它会将消息发送给 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<Types...>“与”std::variant<V1, V2> ()(A)“(又名”variant<变体<A、B>、变体<C、D>>()(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++ 模板 C++20 variadic-templates 变体

评论


答:

2赞 Enlico 9/25/2023 #1

如果希望返回 1,请尝试更改为 。mainV 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 并返回值 Variant

所以你应该想知道“为什么编译器认为我在传递一个指向函数的指针??

好吧,MVP 就是答案:是一个函数的声明,该函数以一个 type 和 return type 的参数命名,该参数具有 type ;当作为参数传递时,该类型会衰减为指向函数等的指针,即 .V cmd(A);cmdAVV(A)V(*)(A)

评论

1赞 Eyal Kamitchi 9/25/2023
为什么我们可以以上帝的名义在函数😭😭中声明函数,而没有机构使用它
2赞 Enlico 9/25/2023
@EyalKamitchi,我现在正在读这篇文章。也许答案就在那里。