Search code examples
c++c++14template-meta-programmingparameter-pack

Access class implementation instanciated from template parameter packs


I would like to instantiate all States in the MachineT as a shared_ptr<T> then access them by typename.

In the following code, it refers to the instantiation (MachineT constructor) and a way to access the states (get function).

Is there any hashmap trick or a way to store in the class an "Index" information such as StateA::Index?

#include <memory>
#include <vector>

template <typename... States>
class MachineT {
 public:
  MachineT() {
    states_.resize(sizeof...(States));
    for (unsigned i = 0; i < states_.size(); ++i) {
      // Instanciate states
      // states_[i].reset(new decltype(State[i])());
    }
  }
  ~MachineT() {}

  class State {
    State(int state_id) : state_id_(state_id) {}
    const size_t state_id_;
  };

  template<typename T>
  std::shared_ptr<T> get() {
    // Retrun the shared_ptr to the State
  }

  std::vector<std::shared_ptr<State>> states_;
};

struct StateA;  // Forward declaration
struct StateB;
using StateMachine = MachineT<StateA, StateB>;

class StateA : StateMachine::State {};
class StateB : StateMachine::State {};

int main(int argc, char const* argv[]) {
  StateMachine sm;

  std::shared_ptr<StateA> state_a = sm.get<StateA>();
  return 0;
}

Solution

  • It's perfectly doable. Here's how to do it in C++14:

    #include <memory>
    #include <tuple>
    
    template <typename... States>
    class MachineT {
     public:
      MachineT()
       : states_{
        std::make_shared<States>()...
      } {
      }
      ~MachineT() {}
    
      template<typename T>
      std::shared_ptr<T> get() {
          return std::get<std::shared_ptr<T>>(states_);
      }
    
      std::tuple<std::shared_ptr<States>...> states_;
    };
    
    struct State1 {};
    
    int main() {
    
        MachineT<State1> a;
        a.get<State1>();
    }
    

    Equivalent of std::get can be implemented with C++11 tools