简体   繁体   中英

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM