双模板参数包

double template parameter pack

这是我的 class 的样子:

template<typename ...events_t, std::uint32_t ...stackDepth>
class Module {
    protected: std::tuple<EventHandler<events_t, stackDepth>...> evtHandlers;
    public: Module(std::tuple<EventHandler<events_t, stackDepth>...> _evtHandlers) : 
         evtHandlers{_evtHandlers}{ /* ... */ }
    // ...
}

我不得不给 EventHandler 一对模板参数,一个是处理的事件类型,另一个是 std::uint32_t 任务的堆栈深度。

双模板参数包无法按原样编译,但我找不到合适的技巧。 有什么办法可以使这项工作干净利落吗?

无法显式提供两个列表,但您可以使用特化来捕获它们:

template<typename A, typename B> class C;
template<typename ...As, typename ...Bs>
class C<std::tuple<As...>, std::tuple<Bs...>>
{
    ...
}

模板可变参数,对于模板 class/struct,必须位于模板参数列表的末尾。所以,直接,你只能用一个。

但是您可以用 std::tuple 包装一个(或两个)可变变量包,用于类型,std::integer_sequence 用于整数值。

不幸的是,你必须使用模板特化:你必须声明主模板接收,例如,几个类型

template <typename, typename>
class Module;

以及使用单个类型名称作为模板包装器的专业化,如下所示

template <typename ... event_t, std::uint32_t ... stackDepth>
class Module<std::tuple<event_t...>, 
             std::integer_sequence<std::uint32_t, stackDepth...>>
 {
   // ...
 };

鉴于您可以在末尾放置一个可变列表,您可以避免第二个包装器,因此,例如,

template <typename, std::uint32_t...>
class Module;

template <typename ... event_t, std::uint32_t ... stackDepth>
class Module<std::tuple<event_t...>, stackDepth...>>
 {
   // ...
 };

如果我理解正确的话,类型 (event_t) 和数字 (stackDepth) 是相关的,并且您有一个接受单一类型的模板 class/struct和一个数字作为模板参数(Event_Handler),我想你可以直接使用 Event_Handler 作为可变参数。

我的意思如下(完整编译示例)

#include <cstdint>

template <typename, std::uint32_t>
struct Event_Handler
 { };

template <typename...>
class Module;

template <typename ... event_t, std::uint32_t ... stackDepth>
class Module <Event_Handler<event_t, stackDepth>...>
 {
   // ...
 };

int main ()
 {
   Module<Event_Handler<int, 0u>, Event_Handler<long, 1u>>  m;
 }

-- 编辑 --

OP 询问

Actually I'd like to take it not as a pure template parameter but as an instance in the constructor. Is this possible with this trick ?

如果我没理解错的话,你正在寻找从 C++17 开始可用的“模板演绎指南”(并且你标记了 C++17,所以应该适合你。

下面是完整的(C++17)编译示例; “显式推导指南”是 main()

之前的结构
#include <cstdint>

template <typename, std::uint32_t>
struct Event_Handler
 { };

template <typename...>
class Module;

template <typename ... event_t, std::uint32_t ... stackDepth>
class Module <Event_Handler<event_t, stackDepth>...>
 {
   public: 
      Module (Event_Handler<event_t, stackDepth>...)
       { }
 };

// explicit deduction guide
template <typename ... event_t, std::uint32_t ... stackDepth>
Module (Event_Handler<event_t, stackDepth>...)
   -> Module<Event_Handler<event_t, stackDepth>...>;

int main ()
 {
   Module  m(Event_Handler<int, 0u>{}, Event_Handler<long, 1u>{});
 }