我正在使用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”计算出数据元素是什么。
答案 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 ) );
}