双模板参数包
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>{});
}
这是我的 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>{});
}