【问题标题】:Specialize a template to only take a typename of a class with template arguments将模板特化为仅采用具有模板参数的类的类型名
【发布时间】:2021-09-24 23:47:56
【问题描述】:

如果我先显示代码,也许最好能理解问题。

#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{};

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

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

问题是我必须访问E 的成员,由于non-type partial specialization 'subscribe&lt;E&lt;MaxSubscribers, Arg_T&gt;, MaxSubscribers, Arg_T&gt;' is not allowed 错误,我的方法不起作用,如果我不专门化subscribe 的模板我无法访问list.

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

编辑

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

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

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;
    }
};

不幸的是,尽管编译器仍然给我一个 list 尚未定义的错误,这意味着模板不够具体,无法阻止错误情况。

【问题讨论】:

    标签: c++ c++11 templates types metaprogramming


    【解决方案1】:

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

    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&lt;..&gt; 之前

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-25
      • 2014-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-26
      • 2012-12-07
      相关资源
      最近更新 更多