【问题标题】:double template parameter pack双模板参数包
【发布时间】:2020-07-02 10:08:46
【问题描述】:

这是我的班级的样子:

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 用于任务的堆栈深度。

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

【问题讨论】:

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


    【解决方案1】:

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

    但是您可以使用 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) 是相关的,并且您有一个模板类/结构接受单一类型和单一数字作为模板参数 ( 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 询问

    其实我不想把它作为一个纯模板参数,而是作为构造函数中的一个实例。用这个技巧可以吗?

    如果我理解正确,您正在寻找从 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>{});
     }
    

    【讨论】:

    • 这是否允许模板类型扣除?我想从一个简单的EventHandlers 元组构建我的module,而不必重新指定他们的stackDepths
    • @Magix - 通过使用 Event_Handlers 的可变参数列表的示例改进了答案。是的,模板类型推导有效。模板号也扣。
    • 这(几乎)创造了奇迹。我仍然需要修复一些错误,但阻塞问题似乎消失了。我感激不尽!
    • 其实我不想把它作为一个纯模板参数,而是作为构造函数中的一个实例。这个技巧有可能吗?我一直在摆弄它但没有成功(见问题编辑)
    • @Magix - 不完全确定理解但......答案有所改善。
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2020-04-29
      • 1970-01-01
      • 2019-10-08
      • 1970-01-01
      • 2021-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-27
      相关资源
      最近更新 更多