将序列的mpl序列转换为trie

时间:2013-02-19 12:55:14

标签: c++ templates boost template-meta-programming boost-mpl

问题看起来很简单,基本上我有一系列序列,如:

typedef mpl::vector<
  mpl::vector<mpl::_1, mpl::_2>,
  mpl::vector<mpl::_1, mpl::_2, mpl::_3>,
  mpl::vector<mpl::_2, mpl::_1>,
  mpl::vector<mpl::_2, mpl::_2>,
  mpl::vector<mpl::_2, mpl::_2, mpl::_3>
> seq;

我想做的是将其转换为trie,最终结果如下:

mpl::map<
  mpl::pair<mpl::_1, 
    mpl::map<
      mpl::pair<mpl::_2,
        mpl::map<
          mpl::pair<TERMINAL, T>,
          mpl::pair<mpl::_3,
            mpl::map<
              mpl::pair<TERMINAL, T>
            >
          >
        >
      >
    >
  >
  mpl::pair<mpl::_2, 
    mpl::map<
      mpl::pair<mpl::_1,
        mpl::map<
          mpl::pair<TERMINAL, T>
        >
      >,
      mpl::pair<mpl::_2,
        mpl::map<
          mpl::pair<TERMINAL, T>,
          mpl::pair<mpl::_3,
            mpl::map<
              mpl::pair<TERMINAL, T>
            >
          >
        >
      >
    >
  >
>

所以,问题是,这是否可能(我认为不是)?如果有可能,我错过了哪些黑暗法术?

编辑:如果从序列序列到trie的上述转换不明确,让我看看我是否可以用简单的英语说明(通常更难)。主要序列中的每个序列基本上由一些类型组成(_1_2等。转换后的版本是trie,其中共同的前缀被折叠。可能是附图有帮助..

resulting tree

EDIT2:感谢@Yakk,希望现在问题更加明确......

2 个答案:

答案 0 :(得分:6)

你去了:

struct Terminal;

template < typename Trie, typename First, typename Last,
           typename Enable = void >
struct insertInTrie_impl
{
    typedef typename
        mpl::deref<First>::type key;

    typedef typename 
        mpl::at<
            Trie,
            key
        >::type subTrieOrVoid; // would be easier if "at" supported Default

    typedef typename
        mpl::if_<
            boost::is_same< subTrieOrVoid, mpl::void_ >,
            mpl::map<>,
            subTrieOrVoid
        >::type subTrie;

    typedef typename
        mpl::insert<
            Trie,
            mpl::pair<
                key, typename
                insertInTrie_impl<
                    subTrie, typename
                    mpl::next<First>::type,
                    Last
                >::type
            >
        >::type type;
};

template < typename Trie, typename First, typename Last >
struct insertInTrie_impl< Trie, First, Last, typename 
    boost::enable_if< boost::is_same<First, Last> >::type >
    : mpl::insert<
        Trie,
        mpl::pair< Terminal, Terminal >
        // I'm not sure what you want in your terminal node
    >
{};

template < typename Trie, typename Seq >
struct insertInTrie
    : insertInTrie_impl< 
        Trie, typename 
        mpl::begin<Seq>::type, typename 
        mpl::end<Seq>::type
    >
{};


template < typename SeqOfSeq >
struct constructTrie
    : mpl::fold< 
        SeqOfSeq,
        mpl::map<>,
        insertInTrie< mpl::_1, mpl::_2 >
    >
{};

insertInTrie_impl是一个递归元函数,它使用迭代器将序列插入到现有的trie中。 insertInTrie接受一个调用insertInTrie_impl的序列。 constructTrieinsertInTrie应用于给定序列中的所有序列,从空的trie开始。

在伪代码中,内容如下:

Trie insertInTrie_impl(trie, first, last)
{
    if (first == last)
    {
        trie.insert(Terminal, Terminal);
        return trie;
    }

    key = *first;

    subTrie = trie[key];
    if (subTrie = void) // key not found
    {
        subTrie = emptyTrie;
    }

    trie.insert(key, insertInTrie_impl(subTrie, ++first, last))

    return trie;
}

Trie insertInTrie(trie, seq)
{
    return insertInTrie_impl(trie, seq.begin(), seq.end();
}

Trie constructTrie(seqOfSeq)
{
    return fold(seqOfSeq, emptyTrie, insertInTrie);
}

最后,使用示例:

int main()
{
    typedef mpl::vector<
        mpl::vector<mpl::_1, mpl::_2>,
        mpl::vector<mpl::_1, mpl::_2, mpl::_3>,
        mpl::vector<mpl::_2, mpl::_1>,
        mpl::vector<mpl::_2, mpl::_2>,
        mpl::vector<mpl::_2, mpl::_2, mpl::_3>
    > seqOfSeq;

    typedef constructTrie< seqOfSeq >::type bigTrie;

    BOOST_MPL_ASSERT(( 
        mpl::has_key<
            mpl::at< 
                mpl::at< 
                    bigTrie, 
                    mpl::_1
                >::type, 
                mpl::_2
            >::type, 
            Terminal
        > ));
    BOOST_MPL_ASSERT(( 
        mpl::has_key<
            mpl::at< 
                mpl::at< 
                    mpl::at< 
                        bigTrie, 
                        mpl::_1
                    >::type,
                    mpl::_2
                >::type, 
                mpl::_3
            >::type, 
            Terminal
        > ));
    BOOST_MPL_ASSERT(( 
        mpl::has_key<
            mpl::at< 
                mpl::at< 
                    bigTrie, 
                    mpl::_2
                >::type,
                mpl::_2
            >::type, 
            Terminal
        > ));
}

答案 1 :(得分:1)

所以答案是“是的,这是可能的”。

写add_to_trie。它需要一个可能为空的trie和一个元素(一系列类型)并返回一个添加了该元素的trie。

测试一个空的trie和一些序列的add_to_trie,以及一些其他手工制作的案例。公共前缀:(“A”)(“A”,“B”),没有公共前缀:(“A”,“A”)(“B”,“A”),较短没有公共前缀:(“A” ,“B”)(“B”),同一件事的两个副本:(“A”)(“A”)等

写累积。它需要一个值和一个二元仿函数和一个序列。如果在序列的每个元素s上应用value = functor(value,s),则返回值。

通过将1到5相加并打印结果来测试累积。

撰写两个。

这可能会破坏你的模板递归堆栈,并且每个步骤都是非常简单的,但是它可以正常工作。但是它会起作用。

首先在字符串上编写上述操作可能会有所帮助。然后使功能起作用。然后转换为对类型进行操作。

我甚至打赌boost已经写好了accumulate的钱。