Creating a hash queue with a variation pattern

I want to create a hash code queue using a variational pattern. Minimal code example

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

When compiling, I get

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

How can i solve this? I do not want to instantiate types. These types will be object classes with constructor classes.

+5
source share
3 answers

Disambiguate using the second argument of the template:

 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); } 
+6
source

It is also possible not to use recursion at all, but instead, deploy the package to std::initializer_list , and then insert it into the queue with the loop.

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

Or even shorter:

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

A longer version works even if the package is empty. In short, this is not because range-uses auto inside, which cannot infer a type from an empty initializer list.

Note that this is being queued in the reverse order compared to your sample code. (Give <int, float, double> , it first pushes int and double last, your code presses double first and int last.) If this is undesirable, use a longer form (optionally replacing std::initializer_list<size_t> with auto ) and manual cycle:

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

or in 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 ); } 
+5
source

You can use std::enable_if as follows:

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

See demo

+1
source

Source: https://habr.com/ru/post/1214833/


All Articles