【问题标题】:Boost.MPL transform with state?Boost.MPL 转换状态?
【发布时间】:2012-05-28 23:46:14
【问题描述】:

我有以下 mpl 序列

boost::mpl::vector_c<std::size_t, 0, 1, 2, 0, 1, 0>

我需要根据以下算法(运行时版本)对其进行转换:

i=0
output_sequence=[]
for k in (0,...,len(input_sequence)-1):
if input_sequence[k] == 0:
    output_sequence.append(i)
    i=i+1
else:
    output_sequence.append(-1)

我的结果应该是:

boost::mpl::vector_c<std::size_t, 0, -1, -1, 1, -1, 2>

我可以想象至少有两种方法可以在运行时使用 std::transform 或 std::accumulate 来实现, 但不知道如何在编译时使用 mpl 实现相同的结果。对我来说主要问题是 以某种方式存储状态“i”(当前找到的零数)以及输出序列。

非常感谢!

添加

根据 HighCommander4 的回答,我想与大家分享采用的方法。实际上,可以将boost::mpl::fold 与自定义元函数一起使用。与 HighCommander4 相比,唯一的概念变化是 将当前可用的空闲索引打包为不断增长的输出序列的第一个元素。最后可以去掉 使用boost::mpl::pop_font进行类型计算。

#include <boost/mpl/size_t.hpp>
#include <boost/mpl/equal_to.hpp>

#include <boost/mpl/fold.hpp>

#include <boost/mpl/front.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/pop_front.hpp>

#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/at.hpp>

#include <boost/mpl/print.hpp>

namespace mpl=boost::mpl;

struct assign_index
{
                enum { dim_dynamic, dim_static };
                template<typename Output, typename Index,
                         typename Enable = typename mpl::if_<
                                             mpl::equal_to<Index, mpl::size_t<1> >,
                                             mpl::size_t<dim_dynamic>,
                                             mpl::size_t<dim_static> >::type>
                struct apply 
                {
                                typedef typename mpl::push_back<Output, mpl::size_t<-1> >::type type;
                };


                template<typename Output, typename Index>
                struct apply <Output, Index, mpl::size_t<dim_dynamic> >
                {
                                typedef typename mpl::front<Output>::type current;
                                typedef typename mpl::next<current>::type next;
                                typedef typename mpl::push_back<Output, current>::type append_type;
                                typedef typename mpl::push_front<
                                                typename mpl::pop_front<append_type>::type,next
                                                >::type type;
                };              
};

template<class input_sequence>
struct map_indices
{
                // The first element of state0 keeps track of the current index count.
                typedef mpl::vector_c<std::size_t, 0> state0;
                typedef typename mpl::fold<input_sequence, state0, assign_index>::type output_sequence;

                // Remove the first element from the final output sequence
                typedef typename mpl::pop_front<output_sequence>::type type;
};

int main (int argc, const char** argv)
{
                typedef mpl::vector_c<std::size_t, 1, 2, 3, 1, 2, 1> input_sequence;
                typedef map_indices<input_sequence>::type output_sequence;
                int i;
                i=mpl::print<mpl::at_c<output_sequence, 0>::type>();
                i=mpl::print<mpl::at_c<output_sequence, 1>::type>();
                i=mpl::print<mpl::at_c<output_sequence, 2>::type>();
                i=mpl::print<mpl::at_c<output_sequence, 3>::type>();
                i=mpl::print<mpl::at_c<output_sequence, 4>::type>();
                i=mpl::print<mpl::at_c<output_sequence, 5>::type>();
                return 0;
}

PS:在这个实现中,输入序列中的“1”被转换为递增索引,而大于 1 的值被转换为 std::size_t(-1)。输入序列中不允许有零(在别处检查)。

PS2:我已经检查过,boost::mpl 中确实没有工具可以将任意mpl 序列(作为算法的结果)转换回boost::mpl::vector。因此它是 也有必要为此编写代码......我最终调整了代码

<boost/fusion/container/vector/detail/as_vector.hpp>

对类型计算结果进行“规范化”。

再次感谢您!

【问题讨论】:

  • 您想开始使用递归重写您的算法。答案应该会变得更加清晰。

标签: c++ templates boost-mpl


【解决方案1】:

模板元编程确实需要一些时间来适应。

注意循环是如何变成递归的,if 语句是如何变成模板特化的,而“状态”是如何变成额外的模板参数的:

#include <cstddef>
#include <boost/mpl/print.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/size.hpp>

using boost::mpl::vector_c;
using boost::mpl::push_back;
using boost::mpl::pop_front;
using boost::mpl::front;
using boost::mpl::int_;
using boost::mpl::size;

typedef vector_c<std::size_t, 0, 1, 2, 0, 1, 0> input_sequence;

template <int i, int current>
struct next_i
{
    static const int value = i;
};

template <int i>
struct next_i<i, 0>
{
    static const int value = i + 1;
};

template <int i, int current>
struct next_output
{
    static const int value = -1;
};

template <int i>
struct next_output<i, 0>
{
    static const int value = i;
};

template <typename rest_of_input, int rest_of_input_size, int i, typename output_so_far>
struct loop
{
    typedef typename front<rest_of_input>::type current_t;
    static const int current = current_t::value;
    static const int next_i_ = next_i<i, current>::value;
    static const int next_output_ = next_output<i, current>::value; 

    typedef typename loop<
            typename pop_front<rest_of_input>::type,
            rest_of_input_size - 1,
            next_i_,
            typename push_back<output_so_far, int_<next_output_> >::type 
    >::type type;
};

template <typename rest_of_input, int i, typename output_so_far>
struct loop<rest_of_input, 0, i, output_so_far>
{
    typedef output_so_far type;
};

template <typename input>
struct algorithm
{
    typedef typename size<input>::type size_;
    typedef typename loop<input, size_::value, 0, vector_c<std::size_t> >::type type;
};

typedef algorithm<input_sequence>::type output_sequence;

int main()
{
    boost::mpl::print<output_sequence>();
}

这可能写得更好(也许用mpl::fold)。

【讨论】:

  • 可能使用fold,因为这是所有转换的基础。在 MPL 疯狂的日子里,我学习了一点 Haskell,这样我就可以在尝试将它们转换为模板之前尝试我的算法......而fold 是所有循环的基础。
  • 我期待更简单的东西!无论如何,IMO 的答案清楚地解释了实现预期结果所需的 TMP“思维”。如果有的话,我唯一的抱怨是输出序列不是 mpl::vector_c<:size_t ...> 而是一个“概念等效”的野兽,其类型是: boost::mpl::v_item, boost::mpl::v_item<:int_>, boost::mpl::v_item<:int_>, boost::mpl::v_item, boost::mpl::v_item<:int_>, boost::mpl::v_item<:int_>, boost::mpl::vector_c, 0>, 0>, 0>, 0>, 0>, 0> !
猜你喜欢
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-07
  • 1970-01-01
  • 2013-11-21
  • 2020-04-12
  • 2018-09-06
相关资源
最近更新 更多