0

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 which 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.

EDIT

I actually found a way how to remove the partial specialization error.

As this post says, the thing I want to do with this function is not possible. So I decided to just use a struct to wrap the function. This looks like this:

template<typename E, typename Valid=void>
struct Subscriptor
{
};

template<typename E>
struct Subscriptor<E, typename std::enable_if<std::is_base_of<Event<E::MaxSubscribers, typename E::Arg_T>, E>::value>::type>
{
    void subscribe(std::function<void(typename E::Arg_T)> callback)
    {
        subscriberMap<E::MaxSubscribers, typename E::Arg_T>::events<E>::list[0] = callaback;
    }
};

Unfortunately though the compiler still gives me an error that list has not been defined, which means the template is not specific enough to stop the error case.

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Gian Laager
  • 474
  • 4
  • 14

1 Answers1

0

Not sure what you want, but syntax would be

template<template<size_t, typename> typename E, size_t MaxSubscribers, typename Arg_T>
void subscribe(std::function<void(Arg_T)> callback)
{
    subscriberMap<MaxSubscribers, Arg_T>::template events<E<MaxSubscribers, Arg_T>>::list[0] = callback;
}

Demo

Note: template is needed before events<..>

Jarod42
  • 203,559
  • 14
  • 181
  • 302