压平一系列序列(序列)

时间:2010-12-07 08:50:37

标签: c++ boost boost-fusion

我正在使用boost :: fusion。

假设我有以下内容:

make_vector(1, make_vector('b', 3, make_vector(4, 5.5), "six"), 7, 8)

我想生成一个函数f,使

f(make_vector(1, make_vector('b', 3, make_vector(4, 5.5), "six"), 7, 8)) 
-> [1, 'b', 3, 4, 5.5, "six", 7, 8]

即。序列的扁平版本。

我不介意这是原始序列的视图还是实际的矢量。

如果可以在GCC 4.5.1上编译,我不介意C ++ 0x中的解决方案。

注意:

虽然我不想限制数据元素,但如果有帮助,可以随意要求“数据”元素都来自公共基类。

class DataBase {}

template <class T>
class Data : public DataBase
{
public:
  Data(const T& x) : m_x(x)
  T m_x;
}

template <class T>
T make_data(const T& x) { return Data<T>(x); }

然后

make_vector(
  make_data(1), 
  make_vector(
    make_data('b'), 
    make_data(3), 
    make_vector(
      make_data(4), 
      make_data(5.5)
    ), 
    make_data("six")
  ), 
  make_data(7), 
  make_data(8)
)

我想你可以使用“is_base_of”计算出数据元素是什么。

1 个答案:

答案 0 :(得分:8)

这是一种可能的解决方案,递归使用join。基本上,它执行以下操作(在伪Haskell中):

flatten []     = []
flatten x      = [x]
flatten (x:xs) = flatten x ++ flatten xs

递归地,扁平的头部与扁平的尾部连接。

这个解决方案很可能不是最有效的解决方案,因为它构建了许多视图,即使对于单个值也是如此;更好的方法是将结果序列作为递归调用中的参数传递,并直接在其中添加单个元素,可能使用fold

这是代码(免责声明:我写得很快,所以代码可能充满了错误和/或非惯用的做事方式):

namespace result_of
{
    template < typename Begin, typename End, class Enable = void >
    struct flatten_impl
    {
        typedef boost::fusion::single_view< typename 
            boost::fusion::result_of::value_of< Begin >::type 
        > flattenedHeadSequence;

        typedef typename 
            flatten_impl< typename
                boost::fusion::result_of::next< Begin >::type,
                End
            >::type flattenedTailSequence;

        typedef typename boost::fusion::result_of::join< const flattenedHeadSequence, const flattenedTailSequence >::type type;
    };


    template < typename Begin, typename End >
    struct flatten_impl< 
        Begin, 
        End, typename
        boost::enable_if< 
            boost::fusion::traits::is_sequence< typename
                boost::fusion::result_of::value_of< Begin >::type
            >
        >::type 
    >
    {
        typedef typename boost::fusion::result_of::value_of< Begin >::type headSequence;
        typedef typename 
            flatten_impl< typename
                boost::fusion::result_of::begin< headSequence >::type, typename
                boost::fusion::result_of::end< headSequence >::type 
            >::type flattenedHeadSequence;

        typedef typename 
            flatten_impl< typename
                boost::fusion::result_of::next< Begin >::type,
                End
            >::type flattenedTailSequence;

        typedef typename boost::fusion::result_of::join< const flattenedHeadSequence, const flattenedTailSequence >::type type;
    };


    template < typename End, typename Enable >
    struct flatten_impl< End, End, Enable >
    {
        typedef boost::fusion::vector< > type;
    };


    template < typename Sequence >
    struct flatten
    {
        typedef typename 
            flatten_impl< typename 
                boost::fusion::result_of::begin< Sequence >::type, typename 
                boost::fusion::result_of::end< Sequence >::type 
            >::type type;
    };    
}


template < typename Begin, typename End >
typename result_of::flatten_impl< Begin, End >::type 
flatten_impl( 
    const Begin & begin, 
    const End & end, typename 
    boost::disable_if<
        boost::fusion::traits::is_sequence< typename
            boost::fusion::result_of::value_of< Begin >::type
        >
    >::type * dummy = 0 )
{
    typedef result_of::flatten_impl< Begin, End > traits;
    typedef typename traits::flattenedHeadSequence headSequence;
    typedef typename traits::flattenedTailSequence tailSequence;

    return boost::fusion::join( 
        headSequence( boost::fusion::deref( begin ) ),
        flatten_impl( boost::fusion::next( begin ), end ) );
}


template < typename Begin, typename End >
typename result_of::flatten_impl< Begin, End >::type 
flatten_impl( 
    const Begin & begin, 
    const End & end, typename 
    boost::enable_if<
        boost::fusion::traits::is_sequence< typename
            boost::fusion::result_of::value_of< Begin >::type
        >
    >::type * dummy = 0 )
{
    typedef result_of::flatten_impl< Begin, End > traits;
    typedef typename traits::flattenedHeadSequence headSequence;
    typedef typename traits::flattenedTailSequence tailSequence;

    typedef typename boost::fusion::result_of::value_of< Begin >::type headType;

    const headType & head = boost::fusion::deref( begin );

    return boost::fusion::join(
        flatten_impl( boost::fusion::begin( head ), boost::fusion::end( head ) ),
        flatten_impl( boost::fusion::next( begin ), end ) );
}


template < typename End >
typename result_of::flatten_impl< End, End >::type
flatten_impl( const End &, const End &)
{
    return boost::fusion::make_vector( );
}


template < typename Sequence >
typename result_of::flatten< Sequence >::type 
flatten( const Sequence & seq )
{
    return flatten_impl( boost::fusion::begin( seq ), boost::fusion::end( seq ) );
}