2015-03-06 24 views
5

Tôi muốn xây dựng một hàng đợi mã băm bằng cách sử dụng mẫu variadic. Ví dụ mã tối thiểu làTạo hàng đợi băm với mẫu variadic

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

On biên dịch tôi nhận được

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

Làm thế nào tôi có thể giải quyết này? Tôi không muốn tạo các phiên bản của các loại. Những loại sẽ là lớp đối tượng với các lớp constructor

Trả lời

6

disambiguate sử dụng một mẫu số thứ hai:

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

Cảm ơn! Làm cách nào tôi có thể bao gồm lệnh gọi 'hash_queue (q);'? – ztik

+0

Rất tiếc, đã sửa trong bản chỉnh sửa của tôi. – TartanLlama

1

Bạn có thể sử dụng std::enable_if như sau:

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

Xem demo

5

Đó là cũng có thể không sử dụng đệ quy ở tất cả, và thay vào đó đóng gói mở rộng thành một std::initializer_list và sau đó đẩy vào hàng đợi bằng một vòng lặp.

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

Hoặc thậm chí ngắn hơn:

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

Phiên bản còn hoạt động ngay cả khi các gói trống. Ngắn hơn không vì phạm vi sử dụng auto nội bộ, không thể suy ra loại từ danh sách bộ khởi tạo trống.

Lưu ý rằng điều này đẩy vào hàng đợi theo thứ tự ngược lại so với mã ví dụ của bạn. (Cho <int, float, double>, nó đẩy int đầu tiên và double trước; mã của bạn đẩy double đầu tiên và int ngoái.) Nếu đó là mong muốn, bằng cách sử dụng hình thức lâu hơn (tùy chọn thay thế std::initializer_list<size_t> với auto) và vòng tay:

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

hoặc trong 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

Tuyệt vời! Không bao giờ nghĩ đến 'std :: initializer_list', tôi thích cái ngắn hơn – P0W