Search code examples
c++c++11templatesvariadic

C++11 Variadic Class Handler Manager


I'm trying to create a template class (event class manager) that will instantiate multiple event class objects. I'm able to get it work for one class, but not able to get it work in the variadic case. I'm trying to get the class_mgr class to take in a list of event classes. For each one, I would like an entry in the std::array.

#include <array>

class handler {
public:
    void handle() {} 
};



enum event_class_types {
    eclass1 = 0,
    eclass2,
    num_classes,
};



class base {
};


template<typename handlerType>
class event_class1 : public base {
public:
    event_class1(handlerType& handler) : 
        handler_(handler) {}
private:
    handlerType& handler_;
};

template<typename handlerType>
class event_class2 : public base {
public:
    event_class2(handlerType& handler) : 
        handler_(handler) {}
private:
    handlerType& handler_;
};


namespace map {
    template<typename handlerType>
    struct event_class1 {
        using type = ::event_class1<handlerType>;
        static constexpr int id = eclass1;
    };

    template<typename handlerType>
    struct event_class2 {
        using type = ::event_class2<handlerType>;
        static constexpr int id = eclass2;
    };
}


//TODO: variadic
template<typename handlerType, template< typename T> class mapTypes>
class event_class_mgr 
{
public:
    event_class_mgr(handlerType& handler) : 
        handler_(handler)
    {
        add_class();
    }

private:
    void add_class( ) 
    {
        my_classes_[ mapTypes<handlerType>::id ] = new typename mapTypes<handlerType>::type(handler_);
    }


    handlerType handler_;
    std::array< base*, event_class_types::num_classes> my_classes_{};
};



int main(int argc, char** argv) {

    handler my_handler;

    event_class_mgr<handler, map::event_class1> cm(my_handler);
    //Trying to make this variadic, to pass multiple types to my handler
    //class_mgr<handler, map::event_class1, map::event_class2> cm(my_handler);
    //alternatively, i could just pass the enums?
    //class_mgr<handler, event_eclass1, event_eclass2> cm(my_handler);
    return 0;
};

Solution

  • If I got what you mean, it's straightforward.
    Just turn the class template declaration to:

    template<typename handlerType, template< typename T> class... mapTypes>
    class event_class_mgr {
        // ...
    }
    

    Then update the add_class member function:

    void add_class( ) 
    {
        using accumulator_type = int[];
        accumulator_type accumulator = { (my_classes_[ mapTypes<handlerType>::id ] = new typename mapTypes<handlerType>::type(handler_), 0)... };
        (void)accumulator;
    }
    

    Using C++17 and thus fold expressions would have reduced the boilerplate, but you explicitly marked the question as C++11, so...

    See it up and running on wandbox.


    As a side note, in C++17 you can write add_class as:

    void add_class( ) 
    {
        ((my_classes_[ mapTypes<handlerType>::id ] = new typename mapTypes<handlerType>::type(handler_)), ...);
    }