2009-05-23 31 views
10

Tôi đã đọc về các nhà soạn nhạc trong 'Thiết kế C++ hiện đại' và tôi hiểu nó như một loại công đoàn cho các loại. Bằng cách đặt các loại khác nhau, không liên quan trong một typelist, người ta có thể sử dụng nó để đại diện cho nhiều hơn một loại cùng một lúc, mà không cần thừa kế. Tôi đã thử nghiệm typelist trong một số chức năng đơn giản với các kiểu nguyên thủy, nhưng tôi không thể nhận được bất kỳ một trong số chúng hoạt động.Cách sử dụng các nhà đánh máy

Ai đó có thể cho tôi biết nếu sự hiểu biết của tôi về typelists là đúng và đưa ra một ví dụ thế giới thực đơn giản làm thế nào để sử dụng typelists trong mã trung bình mỗi ngày? Cảm ơn trước.

Btw, tôi đang sử dụng Windows và Visual Studio 2005 và trình biên dịch của nó.

CHỈNH SỬA: các ví dụ của tôi đã biến mất, tôi sử dụng dự án sandbox để thử nghiệm những điều đó. Nhưng nó đã được yên tĩnh tương tự như mã trong hướng dẫn Dobbs:

void SomeOperation(DocumentItem* p) 
{ 
    if (TextArea* pTextArea = dynamic_cast<TextArea*>(p)) 
    { 
     ... operate on a TextArea object ... 
    } 
    else if (VectorGraphics* pVectorGraphics = 
     dynamic_cast<VectorGraphics*>(p)) 
    { 
     ... operate on a VectorGraphics object ... 
    } 
    else if (Bitmap* pBitmap = dynamic_cast<Bitmap*>(p)) 
    { 
     ... operate on a Bitmap object ... 
    } 
    else 
    { 
     throw "Unknown type passed"; 
    } 
} 

Điều này làm việc nhưng tôi không thấy lợi thế hơn thừa kế có khả năng làm như vậy. Và dàn diễn viên năng động không hoạt động trên các kiểu nguyên thủy. Có thể sử dụng nó làm giá trị trả lại như:

typedef Typelist<int, string> mylist 
mylist myfunction() { 
    if(foo == bar) 
     return 5; 

    return "five"; 
} 
+0

Thêm ví dụ về mã không hoạt động cho câu hỏi của bạn. –

Trả lời

18

Các typelists là các bộ sưu tập kiểu thời gian biên dịch chung. Nếu bạn sử dụng dynamic_cast, bạn đang thiếu điểm, bởi vì nó không cần thiết, bởi vì nó là một khái niệm thời gian tĩnh, biên dịch.

Tác phẩm này nhưng tôi không thấy lợi thế so với thừa kế có khả năng thực hiện tương tự.

Bạn không thể tạo bất kỳ loại hiện có nào kế thừa từ bất kỳ thứ gì bạn muốn. Điều này đơn giản là không khả thi, bởi vì kiểu hiện tại này có thể là một kiểu được xây dựng sẵn hoặc một kiểu từ một thư viện. Hãy nghĩ về các nhà đánh máy như là phần mở rộng của danh sách các loại (ví dụ: trong std :: pair) cho bất kỳ số lượng loại hợp lý nào (thay vì chỉ 2).

Các typelists có thể được sử dụng để tạo ra một cơ sở để truyền xung quanh một tập các đối số cho một hàm.Đây là một đoạn mã gọi các hàm functors chung của 5 tham số (một khái niệm khác từ thiết kế Modern C++) với các đối số được cung cấp trong một tupe (một số khác) với typelist định nghĩa các kiểu đối tượng được giữ trong bộ dữ liệu:

//functor is just a holder of a pointer to method and a pointer to object to call this 
//method on; (in case you are unfamiliar with a concept) 
template<class R, class t0, class t1, class t2, class t3, class t4> 
R call(Loki::Functor<R,LOKI_TYPELIST_5(t0, t1, t2, t3, t4 
    )> func, 
    Loki::Tuple<LOKI_TYPELIST_5(t0, t1, t2, t3, t4)> tuple) 
{ 
    ///note how you access fields 
    return func(Loki::Field<0>(tuple), Loki::Field<1>(tuple), 
     Loki::Field<2>(tuple), Loki::Field<3>(tuple), 
     Loki::Field<4>(tuple)); 
} 

//this uses the example code 
#include<iostream> 
using namespace std; 

int foo(ostream* c,int h,float z, string s,int g) 
{ 
    (*c)<<h<<z<<s<<g<<endl; 
    return h+1 
} 

int main(int argc,char**argv) 
{ 
    Loki::Functor<int,LOKI_TYPELIST_5(ostream*, int, float, string, int)> f=foo; 
    //(...) 
    //pass functor f around 
    //(...) 
    //create a set of arguments 
    Loki::Tuple<LOKI_TYPELIST_5(ostream*, int, float, string, int)> tu; 
    Field<0>(tu)=&cout; 
    Field<1>(tu)=5; 
    Field<2>(tu)=0.9; 
    Field<3>(tu)=string("blahblah"); 
    Field<4>(tu)=77; 
    //(...) 
    //pass tuple tu around, possibly save it in a data structure or make many 
    //specialized copies of it, or just create a memento of a call, such that 
    //you can make "undo" in your application; note that without the typelist 
    //you would need to create a struct type to store any set of arguments; 
    //(...) 
    //call functor f with the tuple tu 
    call(f,tu); 
} 

Lưu ý rằng chỉ với các khái niệm khác như tuple hoặc functors, các typelists bắt đầu có ích. Ngoài ra, tôi đã trải qua Loki khoảng 2 năm trong một dự án và vì mã mẫu (rất nhiều) kích thước của các tệp thi hành trong các phiên bản DEBUG có xu hướng lớn (bản ghi của tôi là 35 MB hoặc hơn). Ngoài ra còn có một chút hit trên tốc độ biên dịch. Cũng nhớ rằng C++ 0x có lẽ sẽ bao gồm một số cơ chế tương đương. Kết luận: cố gắng không sử dụng typelists nếu bạn không phải.

+0

Cảm ơn rất nhiều, bạn đã xóa một số thứ cho tôi. Tôi nghĩ tôi nên đọc lại chương này. – DaClown

5

this Bài viết của Dr. Dobb có giúp được gì không?

4

Máy đánh chữ là cách chuyển "danh sách tham số" cho các chương trình meta mẫu "thực thi" như một phần của quá trình biên dịch.

Như vậy, chúng có thể được sử dụng để tạo ra một loại loại "công đoàn", nhưng đây chỉ là một cách sử dụng có thể.

Ví dụ "thực tế": Chúng tôi đã sử dụng trình đánh máy như một cách để tự động tạo phương thức "QueryInterface" khi triển khai đối tượng COM trong thư viện Comet.

Nó cho phép bạn viết mã như thế này:

class Dog : public implement_qi<make_list<IAnimal, INoisy, IPersistStream> > 
{ 
    // The implement_qi template has provided 
    // an implementation of COM's QueryInterface method for us without 
    // having to write an ugly ATL "message map" or use any Macros. 
    ... 
} 

Trong ví dụ này, "make_list" là một mẫu được sử dụng để tạo ra một "danh sách loại", trong đó các mẫu implement_qi sau đó có thể "liệt kê trên" để generate the appropriate QueryInterface code.

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