使用可变参数模板创建哈希队列
Create hash queue with variadic template
我想使用可变参数模板构建哈希码队列。
最小的示例代码是
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);
}
您可以像下面这样使用 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
也可以完全不使用递归,而是将扩展打包成一个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 );
}
我想使用可变参数模板构建哈希码队列。 最小的示例代码是
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);
}
您可以像下面这样使用 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
也可以完全不使用递归,而是将扩展打包成一个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 );
}