加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 将树编译成元组的编译时间

发布时间:2020-12-16 07:21:36 所属栏目:百科 来源:网络整理
导读:我遇到了以下问题: 给定由Node类型的非终端节点表示的树.和A,B等任意类型的终端节点(见下文). 因为我不想使用runtime-polymorphism,所以我喜欢通过constexpr函数将树转换为std :: tuple,就像下面示例中的立即调用的lambda表达式一样. struct A {};struct B
我遇到了以下问题:

给定由Node<>类型的非终端节点表示的树.和A,B等任意类型的终端节点(见下文).

因为我不想使用runtime-polymorphism,所以我喜欢通过constexpr函数将树转换为std :: tuple,就像下面示例中的立即调用的lambda表达式一样.

struct A {};
struct B {};
struct C {};
struct D {};
struct E {};

template<typename... T>
struct Node {
    constexpr Node(const T&... n) : mChildren{n...} {}
    std::tuple<T...> mChildren;
};

template<uint8_t N>
struct IndexNode {
    std::array<uint8_t,N> mChildren;
};

int main() {
    constexpr auto tree = []() {
        auto t = Node(A(),B(),Node(C(),Node(D())),E());    

        // transform t into std::tuple<A,B,C,D,IndexNode<1>{3},IndexNode<2>{2,4},E,IndexNode<4>{0,1,5,6}>

        // return ...;        
    }();

}

我们的想法是使用元组元素的索引作为树的活动(选定)节点的“指针”.总体目的是在μC上实现菜单系统,而不使用运行时多态性.

如果我可以在编译时执行这个转换,我可以使用一个特殊的元函数来检索活动的元组元素并在其上调用一些函数.我已经写过这个功能了.

缺少的链接肯定会是某种深度优先的树遍历……但我无法弄明白.

解决方法

如何使用大量的std :: tuple_cat,std :: index_sequence和递归如下?

#include <tuple>
#include <array>
#include <iostream>

struct A {};
struct B {};
struct C {};
struct D {};
struct E {};

template <typename... T>
struct Node
 {
   constexpr Node (T const & ... n) : mChildren { n... }
    { }

   std::tuple<T...> mChildren;
 };

template <std::size_t N>
struct IndexNode
 { std::array<uint8_t,N> mChildren; };

template <typename>
struct cntT : public std::integral_constant<std::size_t,1U>
 { };

template <typename ... Ts>
struct cntT<Node<Ts...>>
   : public std::integral_constant<std::size_t,1U + (cntT<Ts>::value + ...)>
 { };

template <typename T>
struct getT
 {
   constexpr auto operator() (T const & t,std::size_t & cnt)
    { ++cnt; return std::make_tuple(t); }
 };

template <typename ... Ts>
struct getT<Node<Ts...>>
 {
   template <std::size_t ... Is>
   constexpr auto func (std::tuple<Ts...> const & t,std::index_sequence<Is...> const &,std::size_t & cnt)
    {
      std::size_t val { cnt };

      IndexNode<sizeof...(Ts)> in
          { { { uint8_t(val += cntT<Ts>::value)... } } };

      return std::tuple_cat(getT<Ts>()(std::get<Is>(t),cnt)...,std::make_tuple(in));
    }

   constexpr auto operator() (Node<Ts...> const & n,std::size_t & cnt)
    {
      return func(n.mChildren,std::make_index_sequence<sizeof...(Ts)>{},cnt);
    }
 };

template <typename ... Ts>
constexpr auto linearNode (Node<Ts...> const & n)
 { 
   std::size_t cnt ( -1 );

   return getT<Node<Ts...>>()(n,cnt);
 }

int main()
 {  
   constexpr auto tree = []()
    {
      auto t = Node { A{},B{},Node{ C{},Node{ D{} } },E{} };

      return linearNode(t);
    }();

   static_assert( std::is_same<
      decltype(tree),std::tuple<A,IndexNode<1>,IndexNode<2>,IndexNode<4>> const>::value,"!");

   std::cout << "IndexNode<1> { ";

   for ( auto const & v : std::get<4U>(tree).mChildren )
      std::cout << int(v) << ",";

   std::cout << "}" << std::endl; // print IndexNode<1> { 3,}

   std::cout << "IndexNode<2> { ";

   for ( auto const & v : std::get<5U>(tree).mChildren )
      std::cout << int(v) << ",";

   std::cout << "}" << std::endl; // print IndexNode<2> { 2,4,}

   std::cout << "IndexNode<4> { ";

   for ( auto const & v : std::get<7U>(tree).mChildren )
      std::cout << int(v) << ",";

   std::cout << "}" << std::endl; // print IndexNode<4> { 0,6,}
 }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读