使用可变参数模板创建哈希队列

Create hash queue with variadic template

本文关键字:创建 哈希 队列 参数 变参      更新时间:2023-10-16

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

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;
}

在编译时我得到

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){

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

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

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);
}

也可以根本不使用递归,而是将 pack 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,无法从空的初始值设定项列表中推断出类型。

请注意,与示例代码相比,这会以相反的顺序推送到队列中。(给<int, float, double>,它会先推送int,最后推送double;你的代码先推送double,最后推送int。如果不需要,请使用较长的形式(可选地将std::initializer_list<size_t>替换为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::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