2012-10-27 4 views
6

Erstens, Entschuldigung für die Ähnlichkeit zu meiner vorherigen Frage here, aber ich glaube nicht, dass ich das Richtige gefragt habe.Wie boost :: fusion :: vector zur Laufzeit füllen?

Ich habe eine Methode:

template <typename T> 
void some_method(T &t) 
{...} 

die fusion::vector<T1, T2, T3, ..., Tn> einen Typ nimmt zur Laufzeit bestimmt werden soll - z.B. vector<int, double> in einem Anruf und vector<int, double, int> in einem anderen.

Ich möchte diesen Vektor dynamisch wie mit etwas füllen:

int blah = 5; 
for(int i = 0; i<size(t); i++){ 
at_c<i>(t) = blah; 
} 

Das funktioniert nicht, da at_c eine const erwartet.

Ich habe andere Sachen ausprobiert (siehe vorherige Frage), kann aber immer noch nicht herausfinden, wie ich das erreichen kann.

Jede Hilfe sehr geschätzt! Danke.

+0

Was ist 'blah'? Eine direkte For-Schleife wird niemals funktionieren, weil 'blah' bei jeder Iteration einen anderen Typ haben muss (Sie müssen eine rekursive Template-Funktion schreiben). Können Sie einige Beispiele dafür geben, wie Sie die einzufügenden Werte darstellen? – Mankarse

+0

Ich gehe davon aus, dass die Werte, die eingefügt werden, in den richtigen Typ umgewandelt werden. Aus Gründen der Argumentation können Sie sich vorstellen, dass 'blah' ein' int' ist. – arlogb

+0

Sie werden nicht zu _runtime_ bestimmt, sie werden zu _compile-time_ bestimmt. –

Antwort

6

Wie @Mankarse korrekt angegeben, Sie kann fusion Behälter in einer for Schleife nicht verwenden, und das ist, weil fusion Behälter alles über tuple sind und jedes Element möglicherweise unterschiedliche Art von hat andere Elemente, alle Funktionen, die durch einen fusion Container durchlaufen, sind eigentlich ein paar Funktionen und normalerweise als template oder überladene Funktionen implementiert. Um also einen fusion Container von vector zu initialisieren, sollten Sie mehrere Funktionen haben (oder einfach eine Vorlage, die zu mehreren Klassen oder Funktionen kompiliert wird), die alle Zugriff auf diesen Vektor haben (oder mindestens einen Iterator von vector und einen Zustand) Variable, die für jeden Aufruf erhöht werden kann). So haben Sie 2 Möglichkeiten:

1) Verwenden Sie boost :: Fusion :: fach:

template< class StdIteratorT > 
struct initialize_fusion_container_from_std_iterator { 
    typedef StdIteratorT result_type; 

    template< class T > 
    StdIteratorT operator()(StdIteratorT i, T& val) { 
     val = *i; 
     return ++i; 
    } 
}; 
void use_fold_demo() { 
    int p1[] = {4, 5, 6}; 
    fusion::vector<int, double, int> fv; 
    std::vector<int> sv2(p1, p1 + _countof(p1)); 
    fusion::fold(fv, sv2.begin(), 
    initialize_fusion_container_from_std_iterator<std::vector<int>::iterator>()); 
} 

2) Schreiben Sie eine Funktion, die sich selbst rekursiv aufrufen mit dem nächsten Punkt des Behälters (erinnern Syntax dieser Funktion ist wie rekursive Funktionen, aber es ist überhaupt nicht rekursiv):

// this will be called when we reach end of the fusion container(FIBeginT==FIEndT) 
template< class FIBeginT, class FIEndT, class StdIteratorT > 
void set_fusion_iterator(FIBeginT b, FIEndT e, StdIteratorT i, boost::mpl::true_) 
{ 
} 
// this will be called when FIBeginT != FIEndT 
template< class FIBeginT, class FIEndT, class StdIteratorT > 
void set_fusion_iterator(FIBeginT b, FIEndT e, StdIteratorT i, boost::mpl::false_) 
{ 
    *b = *i; 
    set_fusion_iterator(fusion::next(b), e, ++i, 
     fusion::result_of::equal_to< 
      typename fusion::result_of::next<FIBeginT>::type, FIEndT >()); 
} 

void recursive_function_demo() { 
    typedef fusion::vector<int, double, int> my_fusion_vector; 

    int p1[] = {1, 2, 3}; 
    std::vector<int> sv1(p1, p1 + _countof(p1)); 
    fusion::vector<int, double, int> fv; 
    set_fusion_iterator(fusion::begin(fv), fusion::end(fv), sv1.begin(), 
     fusion::result_of::equal_to< 
      typename fusion::result_of::end<my_fusion_vector>::type, 
      typename fusion::result_of::begin<my_fusion_vector>::type>()); 
} 

wie Sie zweiten Fall sehen viel komplizierter ist, aber wenn man seine Logik verstehen kann man es etwas mit fusion Containern zu tun verwenden, so dass die Wahl ist alles von dir !!

3

Sie boost::fusion::for_each verwenden:

#include <boost/fusion/algorithm.hpp> 
#include <boost/fusion/container.hpp> 

struct F { 
    F(int blah): blah(blah){} 
    template <typename T> 
    void operator()(T& t) const { 
     t = blah; 
    } 
    int blah; 
}; 

template <typename T> 
void some_method(T &t) 
{ 
    boost::fusion::for_each(t, F(6)); 
} 

int main() { 
    boost::fusion::vector<int, double, int> idi; 
    some_method(idi); 
    boost::fusion::vector<int, double> id; 
    some_method(id); 
} 

In einem Versuch, die for_each entmystifizieren, hier einige meist gleichwertig Code, anstatt numerische Indizes verwendet:

#include <boost/fusion/algorithm.hpp> 
#include <boost/fusion/container.hpp> 
#include <boost/fusion/sequence.hpp> 

template<typename T, int N, int End> 
struct some_method_impl { 
    void operator()(T& t) const { 
     int blah = 6; 
     boost::fusion::at_c<N>(t) = blah; 
     some_method_impl<T, N+1, End>()(t); 
    } 
}; 

template<typename T, int N> 
struct some_method_impl<T,N,N> { 
    void operator()(T& t) const {} 
}; 


template <typename T> 
void some_method(T &t) 
{ 
    some_method_impl<T,0,boost::fusion::result_of::size<T>::type::value>()(t); 
} 

int main() { 
    boost::fusion::vector<int, double, int> idi; 
    some_method(idi); 
    boost::fusion::vector<int, double> id; 
    some_method(id); 
} 
+0

Das ist sehr hilfreich. Eigentlich hast du aber recht, ich hätte etwas genaueres zu "blah" sagen sollen ... Es ist ein 'Vektor ' und ich möchte einen Wert von diesem 'blah' auf den fusion :: vector abbilden. Ist es mit Ihrer vorgeschlagenen Methode möglich? – arlogb

+1

@arlogb: Ja, [zip] (http://www.boost.org/doc/libs/release/libs/fusion/doc/html/fusion/sequence/concepts/random_access_sequence.html) die Sequenz zusammen mit einem Satz von Indizes, und verwenden Sie dann die Indizes, um während des 'for_each' in den Vektor zu indizieren. – Mankarse

0

Wie wäre es damit?

Dies ist ähnlich dem obigen Fall mit boost :: fusion :: for_each .

Aber schneller, wenn ich < Größe (t) als die oben genannten.

Nutzung

main(){ 
    boost::fusion::vector<int,double,std::string,char> vec(9 ,2.2 ,"aaa" ,'b'); 
    std::cout << at_n_dynamic<double>(vec, 1) << std::endl; //=> 2.2 
} 

Körper

#include <boost/fusion/include/vector.hpp>  
template<typename V> 
struct fusion_at_n_functor 
{ 
    mutable int i; 
    int n; 
    mutable V value; 
    fusion_at_n_functor(int _n):i(0),n(_n){} 
    void operator()(const V & t) const 
    { if(i==n){value=t;} i++;} 
    template<typename T> 
    void operator()(const T & t) const 
    { i++;} 
}; 

template <typename First,typename Last,typename AtN > void 
at_n_dynamic_fusion_impl(First i,Last last,AtN &atn,boost::mpl::true_){} 
template <typename First,typename Last,typename AtN > void 
at_n_dynamic_fusion_impl(First i,Last last,AtN &atn,boost::mpl::false_){ 
    if(atn.i == atn.n){atn(boost::fusion::deref(i));} 
    else{ 
    atn(boost::fusion::deref(i)); 
    at_n_dynamic_fusion_impl(boost::fusion::next(i),last,atn, 
      boost::fusion::result_of::equal_to< 
      typename boost::fusion::result_of::next<First>::type,Last> ());} 
} 

template <typename Ret,typename Sequence> Ret 
at_n_dynamic(Sequence & seq, int n){ 
    fusion_at_n_functor<Ret> atn(n); 
#if 0 
    // enabling this if is same to the above case of boost::fusion::for_each 
    boost::fusion::for_each(seq, atn); 
#else 
    // this recursion loop stop at n. but boost::fusion::for_each stop at last 
    at_n_dynamic_fusion_impl(boost::fusion::begin(seq),boost::fusion::end(seq) ,atn, 
     boost::fusion::result_of::equal_to< 
      typename boost::fusion::result_of::begin<Sequence>::type, 
      typename boost::fusion::result_of::end<Sequence>::type>());  
#endif 
    return atn.value;} 

Dies wird Kopie des Boost-Benutzer ML meinen Beitrag http://lists.boost.org/boost-users/2012/08/75493.php http://d.hatena.ne.jp/niitsuma/20120803/1343979718