将模板特化为仅采用带有模板参数的类的类型名

问题描述

也许为了理解问题,我最好先展示代码

#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,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>' 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,E>::value>::type>::list{};

我有数据结构 Event,它用于“索引”subscriberMap,然后将函数添加list。我想检查模板参数 E 是否是 Event 或其任何子类,仅当这是真的 listevents 的成员并且程序编译时。如果 E 不是事件,则程序不应编译。

要向 list 添加函数,请调用函数 subscribesubscribe 需要知道最大订阅者数 MaxSubscribers 和参数的类型 Arg_T,它将传递给 list 中的所有函数。此信息也在作为模板参数 E 传递的 Event 中。

问题是我必须有权访问 E 的成员,我的方法由于错误 non-type partial specialization 'subscribe<E<MaxSubscribers,Arg_T>' is not allowed 而不起作用,如果我没有专门化 {{1} 的模板}} 我无法访问 subscribe

这必须在没有堆分配的情况下完成,除了已经包含的头文件之外,没有库。

编辑

我实际上找到了一种方法来消除 list 错误

正如 this post 所说,我想用这个函数做的事情是不可能的。所以我决定只使用一个结构来包装这个函数。 这看起来像这样:

partial specialization

不幸的是,虽然编译器仍然给我一个错误 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; } }; 尚未定义,这意味着模板不够具体,无法阻止错误情况。

解决方法

不确定你想要什么,但语法是

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

注意:template 之前需要 events<..>