2012-03-10 32 views
11

Andrei Alexandrescu đã có một bài nói chuyện tuyệt vời mang tên: Variadic Templates are Funadic.Mẫu biến thể - các loại mở rộng khác nhau

Ông trình bày 3 mở rộng sau đó là subltey khác nhau:

template <class... Ts> void fun(Ts... vs) { 
    gun(A<Ts...>::hun(vs)...); 
    gun(A<Ts...>::hun(vs...)); 
    gun(A<Ts>::hun(vs)...); 
} 

Ông giải thích:

Gọi 1: Mở rộng tất cả Ts cho instatiation của class A, Sau đó gọi hun(vs) Sau đó mở rộng tất cả các thông số một lần nữa khi chuyển chúng vào gun

Gọi 2: Mở rộng tất cả Ts và tất cả vs riêng

Gọi 3: Expnads trong bước khóa, ví dụ: Mở rộng tranh luận 1 trong tổng số Ts và Đối số 1 của vs Mở rộng tranh luận 2 Ts và đối số 2 của vs Mở rộng đối n của Ts và lập luận n của vs

thảo luận khác về templ variadic ates chỉ dường như bao gồm các mẫu lớp đơn giản của variadic và các hàm variadic như typesafe printf, v.v. Tôi không chắc chắn về cách các kiểu mở rộng khác nhau này có hiệu lực như thế nào và mỗi loại sẽ hữu ích ở đâu.

Có ai có một số ví dụ minh họa ứng dụng của từng loại mở rộng không?

+0

bản sao có thể có của [Mở rộng gói mẫu biến thể] (http://stackoverflow.com/questions/9182251/variadic-templates-pack-expansions) – kennytm

+0

@KennyTM không trùng lặp. Anh chàng này muốn ví dụ về từng loại mở rộng (không nhất thiết chỉ là ba kiểu mà alexandrescu đã cho thấy, và những gì anh ta chỉ cho thấy hai kiểu mở rộng (một trong một danh sách đối số mẫu và một trong danh sách đối số hàm)). –

+1

... nhưng khi ông chấp nhận câu trả lời chỉ cho thấy hai loại mở rộng này, tôi đoán câu hỏi là không chính xác hoặc tôi thiếu hiểu biết về các câu hỏi hoặc cả hai ... –

Trả lời

15
#include <iostream> 
#include <memory> 
#include <typeinfo> 
#include <cstdlib> 
#include <cxxabi.h> 

template <typename T> 
std::unique_ptr<char, void(*)(void*)> 
type_name() 
{ 
    return std::unique_ptr<char, void(*)(void*)> 
      (
       __cxxabiv1::__cxa_demangle(typeid(T).name(), nullptr, 
              nullptr, nullptr), 
       std::free 
      ); 
} 

void display() {} 

template <class T> 
void 
display() 
{ 
    std::cout << type_name<T>().get() << ' '; 
} 

template <class T, class T2, class ...Tail> 
void 
display() 
{ 
    std::cout << type_name<T>().get() << ' '; 
    display<T2, Tail...>(); 
} 

template <class... Ts> 
struct A 
{ 
    template <class... Us> 
     static 
     int 
     hun(Us... us) 
     { 
      std::cout << "A<"; 
      display<Ts...>(); 
      std::cout << ">::hun("; 
      display<Us...>(); 
      std::cout << ")\n"; 
      return 0; 
     } 
}; 

template <class ...T> 
void gun(T...) {} 

template <class... Ts> void fun(Ts... vs) 
{ 
    std::cout << "gun(A<Ts...>::hun(vs)...);\n"; 
    gun(A<Ts...>::hun(vs)...); 
    std::cout << "\ngun(A<Ts...>::hun(vs...));\n"; 
    gun(A<Ts...>::hun(vs...)); 
    std::cout << "\ngun(A<Ts>::hun(vs)...);\n"; 
    gun(A<Ts>::hun(vs)...); 
} 

int main() 
{ 
    fun(1, 'a', 2.3); 
} 

Output:

gun(A<Ts...>::hun(vs)...); 
A<int char double >::hun(int) 
A<int char double >::hun(char) 
A<int char double >::hun(double) 

gun(A<Ts...>::hun(vs...)); 
A<int char double >::hun(int char double) 

gun(A<Ts>::hun(vs)...); 
A<int >::hun(int) 
A<char >::hun(char) 
A<double >::hun(double) 
+0

Việc mở rộng thứ hai có vẻ thẳng về phía trước. 2 khác là thú vị nhưng có lẽ sẽ dẫn đến nhầm lẫn nếu được sử dụng trong mã sản xuất. Bạn có hy vọng sẽ thấy điều này trong một kịch bản thế giới thực? – mark

+4

Thật khó cho tôi để nói. Tôi đoán chúng tôi là một ngành công nghiệp có lẽ vẫn đang học cách sử dụng các mẫu variadic. Một vài năm kể từ bây giờ ai đó có thể khám phá ra một cách thực sự tiện lợi để sử dụng hai hình thức khác và nó có thể trở thành một khuôn mẫu.Vào năm 98, tôi sẽ không bao giờ đoán rằng tôi sẽ sử dụng những thứ như 'enable_if' và tôi vẫn làm tất cả các thời gian bây giờ. C++ là một ngôn ngữ sống và đang phát triển! :-) –

7

Các trường hợp 2 và 3 thực sự là rất phổ biến trong bất kỳ loại mã liên quan đến gói variadic.

template<typename... T> 
void f(T&&... t) 
{ 
    // Case 2: 
    auto t2 = std::tuple<T...>(t...); 

    // Case 3: 
    auto t3 = std::make_tuple(std::forward<T>(t)...); 
} 

Nhìn vào mã của riêng tôi, tôi không thể tìm thấy bất kỳ ví dụ còn lại của trường hợp 1. Tôi có thể đã sử dụng nó trong quá khứ ở một số detail namespace cho một tempate helper, nhưng tôi không chắc chắn. Tôi không nghĩ rằng nó sẽ là phổ biến hoặc thậm chí cần thiết hầu hết thời gian.

+0

Cảm ơn các ví dụ – mark

Các vấn đề liên quan