【问题标题】:Create hash queue with variadic template使用可变参数模板创建哈希队列
【发布时间】:2015-05-08 03:51:00
【问题描述】:

我想使用可变参数模板构建一个哈希码队列。 最小的示例代码是

template<typename T>
void hash_queue(queue<size_t>& q){
  q.push( typeid(T).hash_code() );
}

template<typename T, typename... Ts>
void hash_queue(queue<size_t>& q){
  hash_queue<Ts...>(q);
  q.push( typeid(T).hash_code() );
}

int main(){
  queue<size_t> q;
  hash_queue<int, float, double>(q);
  return 0;
}

在编译时我得到 ​​p>

main.cpp: In instantiation of ‘void hash_queue(std::queue<long unsigned int>&) [with T = float; Ts = {double}]’:
main.cpp:19:22:   required from ‘void hash_queue(std::queue<long unsigned int>&) [with T = int; Ts = {float, double}]’
main.cpp:25:35:   required from here
main.cpp:19:22: error: call of overloaded ‘hash_queue(std::queue<long unsigned int>&)’ is ambiguous
   hash_queue<Ts...>(q);
                      ^
main.cpp:19:22: note: candidates are:
main.cpp:13:6: note: void hash_queue(std::queue<long unsigned int>&) [with T = double]
 void hash_queue(queue<size_t>& q){
      ^
main.cpp:18:6: note: void hash_queue(std::queue<long unsigned int>&) [with T = double; Ts = {}]
 void hash_queue(queue<size_t>& q){

我该如何解决这个问题? 我不想创建类型的实例。这些类型将是带有构造函数类的对象类

【问题讨论】:

    标签: c++ templates c++11 variadic-templates variadic


    【解决方案1】:

    使用第二个模板参数消除歧义:

    template<typename T>
    void hash_queue(queue<size_t>& q){
      q.push( typeid(T).hash_code() );
    }
    
    template<typename T, typename U, typename... Ts>
    void hash_queue(queue<size_t>& q){
      hash_queue<U, Ts...>(q);
      hash_queue<T>(q);
    }
    

    【讨论】:

    • 谢谢!如何包含hash_queue&lt;int, float&gt;(q); 的电话?
    【解决方案2】:

    您可以使用std::enable_if,如下所示:

    template<typename T, typename... Ts>
    void hash_queue( queue<size_t>& q, 
                     typename std::enable_if<sizeof...(Ts)!=0 >::type* = 0 ){
      hash_queue<Ts...>(q);
      q.push( typeid(T).hash_code() );
    }
    

    demo

    【讨论】:

      【解决方案3】:

      也可以完全不使用递归,而是将expand打包成std::initializer_list,然后通过循环推入队列。

      template<typename... Ts>
      void hash_queue(queue<size_t>& q){
        std::initializer_list<size_t> hash_codes = {typeid(Ts).hash_code()...};
        for(auto h : hash_codes)
          q.push( h );
      }
      

      甚至更短:

      template<typename... Ts>
      void hash_queue(queue<size_t>& q){
        for(auto h : {typeid(Ts).hash_code()...})
          q.push( h );
      }
      

      即使包装是空的,较长的版本也可以使用。较短的不是因为 range-for 在内部使用 auto,它无法从空的初始化列表中推断出类型。

      请注意,与您的示例代码相比,这会以相反的顺序进入队列。 (给&lt;int, float, double&gt;,它首先推送int,最后推送double;您的代码首先推送double,最后推送int。) 如果不希望这样做,请使用较长的形式(可选地将 std::initializer_list&lt;size_t&gt; 替换为 auto)并手动循环:

      template<typename... Ts>
      void hash_queue(queue<size_t>& q){
        std::initializer_list<size_t> hash_codes = {typeid(Ts).hash_code()...};
        for(auto p = hash_codes.end(), end = hash_codes.begin(); p != end; --p)
            q.push( *(p-1) );
      }
      

      或在 C++14 中

      template<typename... Ts>
      void hash_queue(queue<size_t>& q){
        std::initializer_list<size_t> hash_codes = {typeid(Ts).hash_code()...};
        for(auto p = rbegin(hash_codes), end = rend(hash_codes); p != end; ++p)
            q.push( *p );
      }
      

      【讨论】:

      • 太棒了!从来没想过std::initializer_list,我喜欢短一点的
      猜你喜欢
      • 1970-01-01
      • 2011-08-28
      • 1970-01-01
      • 1970-01-01
      • 2021-08-27
      • 1970-01-01
      • 2022-09-22
      • 2021-10-01
      • 1970-01-01
      相关资源
      最近更新 更多