c++ - 将可变参数模板参数包解压到函数签名中

标签 c++ templates c++17 variadic-templates

我已经在一个小型库中创建了用于调度和处理事件的类。我的目标是让它尽可能易于使用,避免宏观污染。事件在编译时注册,监听器在运行时订阅事件。两者都由 Resource 中的枚举标识命名空间。 Pack是可变模板参数的存储。 EventInfo是告诉我们将在 Listener 中使用哪些参数的方法和 Event .代码:

namespace Resource 
{
    enum class Resource::EventId;
    enum class Resource::ListenerId;
}

template< class EventId, EventId id >
struct EventInfo;

template< class... Args >
struct Pack
{
};

template< class ListenerId_, class... EventData >
struct Listener
{
    using ListenerId = ListenerId_;

    ListenerId Id = ListenerId::Undefined;
    bool IsEnabled = false;
    std::function< void( EventData... ) > Callback = nullptr;
};

template< class ListenerId_, class... EventData >
struct EventInfoHelper
{
    using Data = Pack< EventData... >;
    using Listener = typename Listener< ListenerId_, EventData... >;
    using ListenerId = typename Listener::ListenerId;
};

#define REGISTER_EVENT_W_ARGS( NAME, ... ) \
template<> \
struct EventInfo< Resource::EventId, Resource::EventId::NAME > \
{ \
public: \
    using Hlpr = EventInfoHelper< Resource::ListenerId, __VA_ARGS__ >; \
    using Data = Hlpr::Data; \
    using Listener = Hlpr::Listener; \
    using ListenerId = Hlpr::ListenerId; \
};

REGISTER_EVENT_W_ARGS( OnUpdate, const sf::Time& );
// ... macro undef here

template< class Id, Id id >
class Event
{
public:
    using Data = typename EventInfo< Id, id >::Data;
    using Listener = typename EventInfo< Id, id >::Listener;
    using ListenerId = typename EventInfo< Id, id >::ListenerId;

    template< class... DataUnpacked, class = std::enable_if_t< std::is_same< Pack< DataUnpacked... >, Data >::value > >
    static void Dispatch( DataUnpacked... data )
    {
        for( auto& listener : m_listeners )
        {
            CHECK( listener.Id != ListenerId::Undefined );
            if( listener.IsEnabled )
            {
                CHECK( listener.Callback != nullptr );
                listener.Callback( data... );
            }
        }
    }

    // ...
private:
    static std::vector< Listener > m_listeners;
};

当前用例:

Event< Resource::EventId, Resource::EventId::OnUpdate >::Dispatch< const sf::Time& >( dt );

期望的(从 EventInfo::Data 推导的参数):

Event< Resource::EventId, Resource::EventId::OnUpdate >::Dispatch( dt );

问题是如何实现Dispatch参数在 EventInfo::Data 中注册作为Pack< Args... >争论?

最佳答案

您提供的代码不完整,因此我无法将解决方案集成到您的示例中。

您可以使用基类从Pack<...>中提取参数包并在基类中的函数中展开

template<typename ...>
class Pack {};

template<typename>
class test_base;

template<typename ... Args>
class test_base<Pack<Args...>> {
    public:
    void Dispatcher(Args... args) {
        //implemntation
    }
};

template<typename ... Args>
class test : public test_base<Pack<Args...>> {
};

关于c++ - 将可变参数模板参数包解压到函数签名中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53642124/

相关文章:

c++ - 这种模板编程技术的名称是什么,这是标准的 C++ 吗?

.net - 如何为通用接口(interface)编写 native 模板化后备存储?

c++ - 我们如何并行运行算法的 n 个实例并以有效的方式计算结果函数的平均值?

c++ - VS 2013 缺少符号 (msvcr120.i386.pdb)

c++ - 如何确保 ActiveX 类中的方法进入 DLL(通过 ITypeLib 检查)

c++ - 用于 DOS 的古老 C++ 编译器和 IDE

c++ - 使用C++ catch框架验证assert语句

python - Django 在正确的文件夹中找不到静态 js 脚本

c++ - C++17 中的模板化 lambda 没有自动参数

c++ - 你可以有constexpr右值吗?