5

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

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>
            >
          >
        >
      >
    >
  >
>

所以,问题是,这可能吗(我认为不可能)?如果可能的话,我错过了哪些黑暗咒语?

编辑:如果上述从序列序列到特里的转换不清楚,让我看看我是否可以用简单的英语陈述它(通常更困难。)基本上主序列中的每个序列都由一些类型(_1等)_2组成.) 转换后的版本是普通前缀被折叠的特里。可能是附图帮助..

结果树

EDIT2:感谢@Yakk,希望现在问题更清楚了......

4

2 回答 2

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_implconstructTrie适用insertInTrie于给定序列中的所有序列,从一个空的 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
        > ));
}
于 2013-02-19T15:27:42.480 回答
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),则返回 value。

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

组成两者。

这可能会破坏您的模板递归堆栈,并且每个步骤要正确编写都不是一件容易的事,但它会起作用。

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

我敢打赌,即使是已经写好boost适当的钱。accumulate

于 2013-02-19T14:10:13.993 回答