2010-12-07 13 views
8

Boost :: fusion kullanıyorum.Bir dizi sekansı (sekansların) düzleştirin

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

böyle bu

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] 

yani dizisinin düzleştirilmiş versiyonu bir fonksiyon f üretmek istediği:

aşağıdaki gibi bir şey olması düşünelim.

Bu, özgün dizinin veya gerçek bir vektörün bir görünümü olup olmadığı umrumda değil.

GCC 4.5.1'de derleme yapabilmesi durumunda C++ 0x çözümüne aldırış etmem.

Not:

Ben veri öğelerini kısıtlamak için tercih ediyorum iken, eğer yardımcı olur, "veri" unsurları bütün ortak temel sınıf türetmek gerektirir çekinmeyin. yani

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); } 

Sonra

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

Ben o zaman "is_base_of" kullanarak veri elemanları ne olduğunu anlamaya çalışabilir.

cevap

8

İşte bir çözüm, join özyinelemeli kullanır.

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

yinelemeli, düzleştirilmiş kafası yassılaştırılmış kuyruğuna birleştirilmiş: Temel olarak, (psödo-Haskell) şunları yapar.

Bu çözüm, tek değerler için bile birçok görünüm oluşturduğundan, en etkili olanı değil; Daha iyi bir yaklaşım, elde edilen diziyi özyinelemeli çağrılardaki bir parametre olarak geçirebilir ve belki de fold kullanarak belki de tek tek elemanları ekleyebilir. (: Ben oldukça hızlı bir şekilde bu yazdım, bu yüzden kod böcek ve/veya şeyler yapmanın olmayan deyimsel yollarla dolu olabilir feragat): Burada

kodudur

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)); 
} 
+0

WOW! Teşekkürler, bunu deneyeceğim ve daha yakından bakacağım. Bu, aradığım boost kaynak kodunun birçoğuna benziyor. Fikrimi Haskell versiyonundan da temel alıyordum, ancak enable_if'in derleme hataları olmadan doğru bir şekilde elde edilemediğini gördüm. – Clinton