2015-03-06 9 views
5

Ich möchte eine Hash-Code-Warteschlange mit variadic Vorlage erstellen. Der minimale Beispielcode istErstellen Sie Hash-Warteschlange mit variadic Vorlage

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

Auf der Kompilierung I

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

bekommen Wie kann ich dieses Problem lösen? Ich möchte keine Instanzen der Typen erstellen. Diese Arten werden Objektklassen mit Konstruktor Klassen

Antwort

6

Disambiguieren unter Verwendung einer zweiten Template-Argument sein:

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

Vielen Dank! Wie kann ich den Aufruf von 'hash_queue (q); '? – ztik

+0

Whoops, in meiner Bearbeitung behoben. – TartanLlama

1

können Sie std::enable_if verwenden wie folgt vor:

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

Siehe demo

5

Es ist Es ist auch möglich, Rekursion überhaupt nicht zu verwenden und stattdessen in a expandieren std::initializer_list und drücken Sie dann mit einer Schleife in die Warteschlange.

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

Oder noch kürzer:

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

Die längere Version funktioniert auch, wenn die Packung leer ist. Die kürzere verwendet nicht, weil der Bereich intern verwendet wird, der den Typ nicht aus einer leeren Initialisierungsliste ableiten kann.

Beachten Sie, dass dies im Vergleich zu Ihrem Beispielcode in umgekehrter Reihenfolge in die Warteschlange geschoben wird. (Gib <int, float, double>, drückt er int erste und double zuletzt; Code schiebt double erste und int letzte.) Wenn die unerwünschte ist, mit der längeren Form (optional std::initializer_list<size_t> mit auto ersetzt) ​​und Schleife manuell:

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

oder 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); 
} 
+0

Großartig! Nie dachte ich an 'std :: initializer_list', ich mochte den kürzeren – P0W