gpt4 book ai didi

c++ - 如何定义 variant 提取模板参数的子类型

转载 作者:太空狗 更新时间:2023-10-29 20:33:16 53 4
gpt4 key购买 nike

我正在构建一个状态机,其中状态转换被描述为一个变体,即:

using table = std::variant<
/* state event followup-state */
transition<start, success<sock>, connecting>,
transition<start, exception, failed>,
transition<connecting, success<>, connected>,
transition<connecting, exception, failed>,
transition<connected, exception, failed>
>;

transition 是一个简单的类型:

template <typename ENTRY_STATE, typename EVENT, typename NEXT_STATE>
struct transition {
using entry_state = ENTRY_STATE;
using event = EVENT;
using next_state = NEXT_STATE;
};

状态类是非多态的(并且不应是)。我现在的问题是如何定义另一个能够存储在表类型中找到的所有可能状态的变体(最好不要重复)。需要该类型以类型安全和非多态的方式存储实际状态。

从上表中,我们有一组独特的进入状态:

entry_states = <start,connecting,connected>

和一组后续状态:

followup_states = <connecting, connected, failed>

因此生成的变体定义应为:

using states = std::variant<entry_states JOINT followup_states>;

=> using states = std::variant<start,connecting,connected, failed>

我知道如何从表中提取类型信息并访问特定转换的类型信息,但不知道如何将可能的状态转换为变体定义(没有重复类型)。

任何想法都会受到赞赏。但是,多态性不是有效的解决方案。在 lambda 中保存当前状态也不是一种选择。

谢谢,最好!

PS:状态机签名看起来像那样(我没有发布完整代码,因为它对问题没有意义,imo):

template <typename TransitionTable, typename Context>
class state_machine {
public:
template <typename State, typename Event>
auto push(State & state, Event & event) {
...
}
protected:
*using states = std::variant<???>;*
states current_state;
};

最佳答案

有两个独立的任务:

  1. 从转换表中提取状态。这可以通过模式匹配轻松完成。
  2. 删除重复项。这可以用 O(log n) 深度完成,复杂性来自 std::tuple_cat,它使用 std::index_sequence,另外直接来自后者。<

合并类型列表的代码作为奖励:

#include <tuple>
#include <utility>
#include <type_traits>

namespace detail {
template <template <class...> class TT, template <class...> class UU, class... Us>
auto pack(UU<Us...>)
-> std::tuple<TT<Us>...>;

template <template <class...> class TT, class... Ts>
auto unpack(std::tuple<TT<Ts>...>)
-> TT<Ts...>;

template <std::size_t N, class T>
using TET = std::tuple_element_t<N, T>;

template <std::size_t N, class T, std::size_t... Is>
auto remove_duplicates_pack_first(T, std::index_sequence<Is...>)
-> std::conditional_t<(... || (N > Is && std::is_same_v<TET<N, T>, TET<Is, T>>)), std::tuple<>, std::tuple<TET<N, T>>>;

template <template <class...> class TT, class... Ts, std::size_t... Is>
auto remove_duplicates(std::tuple<TT<Ts>...> t, std::index_sequence<Is...> is)
-> decltype(std::tuple_cat(remove_duplicates_pack_first<Is>(t, is)...));

template <template <class...> class TT, class... Ts>
auto remove_duplicates(TT<Ts...> t)
-> decltype(unpack<TT>(remove_duplicates<TT>(pack<TT>(t), std::make_index_sequence<sizeof...(Ts)>())));
}

template <template <class...> class TT, class... Ts>
using merge_t = decltype(detail::unpack<TT>(std::tuple_cat(detail::pack<TT>(std::declval<Ts>())...)));

template <class T>
using remove_duplicates_t = decltype(detail::remove_duplicates(std::declval<T>()));

将其应用于您的转换表:

template <template <class...> class TT, class ... Ts>
auto extract_states(TT<Ts...>)
-> TT<typename Ts::entry_state..., typename Ts::next_state...>;

using extracted = decltype(extract_states(std::declval<table>()));
using states = remove_duplicates_t<extracted>;

在 coliru 上实时观看。

关于c++ - 如何定义 variant<x,y,z> 提取模板参数的子类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56253353/

53 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com