C ++ 11 unpack std :: tuple into a virtual member function

Full story:

I am trying to create a structure that looks something like this:

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

Now we can use the framework to define a couple of simple classes that can be modeled.

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

And then build the multiversion of these simulated households ...

 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 (ie fido, sniffles etc.) 

Finally, we get to the point: we want to be able to write a function that is agnostic like a household, but still able to call run to simulate:

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

In short: run calls the corresponding template instance of the execute_simulation_wrapped virtual method, which then decompresses the stored_inputs and provides them with a virtual simulation function that has an individual implementation for each household.


The question I think should be asking is:

So, I think that I have most of the above settings, but I looked at this for a long time, and I still can’t understand how the function simulation_wrapper::execute_simulation_wrapped can make a simulation call and provide the unpacked tuple stored_inputs as a parameter package.

I know that there are SO questions and blogs that contain information on how to call a regular function with an unpacked tuple, but I was not able to extend it to member functions and, in particular, to virtual member functions.

TMP is new to me and still quite confusing, so pretty explicit answers would be much appreciated!

+6
source share
1 answer

This is usually done using 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;}; }; 

If you need index_sequence , available in <utility> only with C ++ 14, you can use the following implementation:

 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

+7
source

Source: https://habr.com/ru/post/979862/


All Articles