2012-02-16 13 views
7

Voglio costruire boost::variant s contenente valori predefiniti, specificati con un indice di tipo - senza scrivere la mia istruzione di commutazione sull'indice di tipo.Costruisce una variante di boost contenente un valore del tipo nesimo nell'indice del tipo di variante?

Immagino che questo sia possibile, in qualche modo, con MPL?

Per chiarire, tuttavia, l'indice non è un'espressione costante in fase di compilazione.

Il caso d'uso è che ho bisogno di costruire una variante che verrà successivamente sostituita con una contenente il valore corretto, ma a questo punto conosco solo l'indice di tipo. Pensala come un problema di deserializzazione pigra.

+0

Dato che si parla di MPL, penserei che 'N' (l'indice di tipo) sia noto in fase di compilazione, tuttavia la deserializzazione pigra suggerisce che potrebbe essere disponibile solo in fase di esecuzione -> qual è? –

+0

@MatthieuM. Questo sarebbe impossibile con il dopo. Spero per il primo, altrimenti la mia risposta è senza valore. – pmr

+0

@MatthieuM. Ah, buon punto: è disponibile solo in fase di esecuzione. – James

risposta

11

È necessario utilizzare il typedef variant::types. Questo ti dà una sequenza MPL compatibile che possiamo usare con mpl::at e un modello per fare le nostre offerte. Questo fa il trucco:

#include <string> 
#include <boost/variant.hpp> 
#include <boost/mpl/at.hpp> 
#include <boost/mpl/int.hpp> 

template<typename U, typename V> 
void construct_in(V& v) { 
    v = U(); 
    // modern 
    // v = U{}; 
} 

int main() 
{ 
    typedef boost::variant<int, std::string> variant; 
    typedef boost::mpl::at<variant::types, boost::mpl::int_<1>>::type pos; 
    variant v; 
    // use type deduction 
    construct_in<pos>(v); 
    // does not throw, does work 
    std::string& s =boost::get<std::string>(v); 
    return 0; 
} 

Qui va il runtime-variante:

#include <string> 
#include <vector> 
#include <functional> 

#include <boost/variant.hpp> 
#include <boost/mpl/at.hpp> 
#include <boost/mpl/int.hpp> 
#include <boost/mpl/for_each.hpp> 

typedef boost::variant<int, std::string> variant; 
typedef variant::types types; 
typedef std::vector< std::function<void(variant&)> > fvec; 

template<typename U, typename V> 
void construct_in(V& v) { 
    v = U{}; 
} 

struct build_and_add { 
    fvec* funcs; 
    template<typename T> 
    void operator()(T) { 
    funcs->push_back(&construct_in<T, variant>); 
    } 
}; 


int main() 
{ 

    variant v; 
    std::vector< std::function<void(variant&)> > funcs; 

    // cannot use a lambda, would need to be polymorphic 
    build_and_add f = {&funcs}; 
    boost::mpl::for_each<types>(f); 

    // this is runtime! 
    int i = 1; 

    funcs[i](v); 
    // does not throw, does work 
    std::string& s =boost::get<std::string>(v); 
    return 0; 
} 

E 'un po' arcano e avrà bisogno di qualche ritocco con variadic argomenti per essere veramente generica, ma fa quello che vuoi . Qualcun altro ha bisogno di capire se questo si traduce in un significativo blow-up del codice .

+0

Ci scusiamo per il chiarimento sull'indice di tipo in fase di esecuzione, ma non credo che questa risposta sia inutile: sarebbe possibile estenderla per passare da N a indici costanti in fase di esecuzione, dove solo N è fisso a compilare il tempo (e può anche essere estratto dalla variante, forse?) – James

+0

@Autopulated Non proprio, ma qualche magia nera potrebbe aiutare. Pensa al modello che usiamo per la costruzione. Possiamo generare tutti questi modelli in fase di compilazione e archiviarli come oggetti 'std :: function' in un vettore e utilizzare questo vettore in fase di runtime per cercare ciò che vogliamo costruire. Proverò a gettare qualcosa insieme, ma non so quanto sarebbe bello in termini di esplosione del codice ecc. – pmr

+0

@ pmr: la mia reazione istintiva è stata quella di usare la ricorsività, ma un vettore (o matrice dal N è costante) del puntatore alle funzioni sembra dare una garanzia di prestazione molto migliore (non fare affidamento su un'eventuale ricorsione in coda). Potresti aver bisogno di una ricorsione per l'inizializzazione del vettore, ma è una cosa a parte. –

Problemi correlati