2014-12-18 13 views
6

La storia completa:C++ 11 disfare std :: tuple nella funzione membro virtual

Sto cercando di costruire un quadro di riferimento che sembra un po 'come questo:

#include <tuple> 
#include <memory> 
using namespace std; 

// this class allows user to call "run" without any args 
class simulation_base{ 
public: 
    int run(){ execute_simulation_wrapped(); }; 
protected: 
    virtual int execute_simulation_wrapped(); {return 0;}; 
} 

// this class funnels some stored inputs into a soon-to-be-overridden method 
template <typename Ts...> 
class simulation_wrapper : public simulation_base { 
    tuple<shared_ptr<Ts>... > stored_inputs; 

    public: 
    int execute_simulation_wrapped() {/* how do you call simulation method? */}; 

    protected: 
    virtual int simulation(const Ts&...){return 0}; 
} 

Ora noi possono utilizzare il framework per definire un paio di classi semplici dall'aspetto che possono essere simulati ..

class jones_household : public simulation_wrapper< woman, girl, cat >{ 
    int simulation(woman mrs_jones, girl mary, cat sniffles) 
     // mrs_jones and her daugther mary play with sniffles the cat 
     return 1; 
    } 
} 

class smith_household : public simulation_wrapper< man, dog >{ 
    int simulation(man mr_smith, dog fido) 
     // mr_smith and his dog fido go for a walk 
     return 1; 
    } 
} 

E poi costruire un multiverso di queste famiglie simulatable ...

smith_household uinverse_1_smiths; 
smith_household uinverse_2_smiths; 
jones_houshold uinverse_1_jones; 
jones_houshold uinverse_2_jones; 

// set the values of the stored_inputs (i.e. fido, sniffles etc.) 

Infine, arriviamo al punto: noi vogliamo essere in grado di scrivere una funzione che è agnostica di tipo domestico, ma è ancora in grado di chiamare run sulla simulazione:

void play_simulation(simulation_base& some_household){ 
    // do some general stuff... 

    some_household.run(); 
} 

In breve:run chiama l'istanza temporizzata pertinente del metodo virtuale execute_simulation_wrapped, che quindi decomprime il stored_inputs e li fornisce alla funzione virtuale simulation che ha un'implementazione personalizzata per ogni nucleo familiare.


La domanda che penso che dovremmo chiedere:

Quindi, penso che ho la maggior parte del proprio sopra set up, ma ho cercato in questo per un molto tempo e non riesco ancora a capire come la funzione simulation_wrapper::execute_simulation_wrapped possa effettuare la chiamata a simulation e fornire la tupla decompressa stored_inputs come un pacchetto di parametri.

So che ci sono SO domande e blog che forniscono dettagli su come chiamare una funzione regolare con una tupla decompressa, ma non sono riuscito a estenderlo alle funzioni membro e in particolare alle funzioni dei membri virtuali.

TMP è nuovo per me e ancora completamente confuso, quindi le risposte abbastanza esplicite sarebbero molto apprezzate!

risposta

7

Questo è solitamente fatto con l'aiuto di index_sequence:

template <typename... Ts> 
class simulation_wrapper : public simulation_base 
{ 
    tuple<shared_ptr<Ts>... > stored_inputs{new Ts...}; 

public: 
// MAGIC STARTS HERE 
    int execute_simulation_wrapped() { return execute_simulation_wrapped(std::make_index_sequence<sizeof...(Ts)>{}); } 

private: 
    template <std::size_t... Is> 
    int execute_simulation_wrapped(std::index_sequence<Is...>) { return simulation(*std::get<Is>(stored_inputs)...); } 
// MAGIC ENDS HERE 

protected: 
    virtual int simulation(const Ts&...){return 0;}; 
}; 

Se avete bisogno di un index_sequence, che è disponibile in <utility> solo a partire dal C++ 14, è possibile utilizzare il seguito dell'attuazione:

template <std::size_t... Is> 
struct index_sequence {}; 

template <std::size_t N, std::size_t... Is> 
struct make_index_sequence_h : make_index_sequence_h<N - 1, N - 1, Is...> {}; 

template <std::size_t... Is> 
struct make_index_sequence_h<0, Is...> 
{ 
    using type = index_sequence<Is...>; 
}; 

template <std::size_t N> 
using make_index_sequence = typename make_index_sequence_h<N>::type; 

DEMO

+0

santo schifo che è stato veloce e utile. fammi dare un'occhiata! ... sì, immagino che sia quello che cercavo. Grazie! –

+0

@ dan-man Ho dovuto modificare leggermente le parti del tuo codice per renderlo compilabile, ma non cambia la soluzione stessa –

+3

Nota che 'std :: make_index_sequence ' può essere sostituito da il suo alias 'std :: index_sequence_for '. – Jarod42

Problemi correlati