jeudi 15 juillet 2021

Spezialize a template to only take a typename of a class with template arguments

Maybe to understand the problem it's best if I first show the code.

#include <type_traits>
#include <functional>
#include <array>

template<size_t MaxSubscribers_, typename T>
struct Event
{
    using Arg_T = T;
    static constexpr size_t MaxSubscribers = MaxSubscribers_;
};

class EventManager
{
public: //TODO: needs to be made private
    template<size_t MaxSubscribers, typename T>
    struct subscriberMap
    {
        template<typename E, typename Valid = void>
        struct events
        {
        };

        template<typename E>
        struct events<E, typename std::enable_if<std::is_base_of<Event<MaxSubscribers, T>, E>::value>::type>
        {
            static std::array<std::function<void(typename E::Arg_T)>, E::MaxSubscribers> list;
        };
    };

public:
    template<typename E, size_t MaxSubscribers, typename Arg_T >
    void subscribe(std::function<void(Arg_T)> callback) = delete;

    template<template<size_t, typename> typename E, size_t MaxSubscribers, typename Arg_T>
    void subscribe<E<MaxSubscribers, Arg_T>, MaxSubscribers, Arg_T>(std::function<void(Arg_T)> callback) // Error non-type partial specialization 'subscribe<E<MaxSubscribers, Arg_T>, MaxSubscribers, Arg_T>' is not allowed
    {
        subscriberMap<MaxSubscribers, Arg_T>::events<E>::list[0] = callabck;
    }
};

template<size_t MaxSubscribers, typename T>
template<typename E>
std::array<std::function<void(typename E::Arg_T)>, E::MaxSubscribers>
EventManager::subscriberMap<MaxSubscribers, T>::events<E, typename std::enable_if<std::is_base_of<Event<MaxSubscribers, T>, E>::value>::type>::list{};

I've got the data structure Event wich is used to "index" subscriberMap and then add functions to list. I want to check if the template parameter E is an Event or any child class of it only when this is true list is a member of events and the program compiles. If E is not an Event the program should not compile.

To add a function to list you call the function subscribe. subscribe needs to know what the maximal number of subscribers MaxSubscribers and the type of the argument, Arg_T,that will be passed to all functions in list. This information is also in the Event that is passed as the template parameter E.

The problem is that I have to have access to the members of E, my approach doesn't work because of the error non-type partial specialization 'subscribe<E<MaxSubscribers, Arg_T>, MaxSubscribers, Arg_T>' is not allowed and if I don't specialize the template of subscribe I can not access list.

This has to be done with no heap allocation and no libraries except the headers that are already included.

Aucun commentaire:

Enregistrer un commentaire