2008-09-15 20 views

Trả lời

24

Tôi đã từng sử dụng lập trình meta mẫu trong C++ để thực hiện một kỹ thuật gọi là "nhiễu loạn biểu tượng" để xử lý đầu vào thoái hóa trong thuật toán hình học. Bằng cách biểu diễn các biểu thức số học như các mẫu lồng nhau (tức là về cơ bản bằng cách viết ra các cây phân tích bằng tay), tôi đã có thể đưa ra tất cả các phân tích biểu thức cho trình xử lý mẫu.

Thực hiện việc này với các mẫu có hiệu quả hơn, ví dụ, viết cây biểu thức bằng cách sử dụng các đối tượng và thực hiện phân tích khi chạy. Nó nhanh hơn bởi vì cây biểu thức đã được sửa đổi (bị xáo trộn) có sẵn cho trình tối ưu hóa ở cùng cấp với phần còn lại của mã của bạn, do đó bạn sẽ có được toàn bộ lợi ích của việc tối ưu hóa, cả trong biểu thức của bạn mà còn (nếu có thể) giữa các biểu thức của bạn và mã xung quanh.

Tất nhiên bạn có thể thực hiện điều tương tự bằng cách triển khai một DSL nhỏ (ngôn ngữ miền cụ thể) cho biểu thức của bạn và dán mã C++ đã dịch vào chương trình thông thường của bạn. Điều đó sẽ mang lại cho bạn tất cả các lợi ích tối ưu hóa giống nhau và cũng dễ đọc hơn - nhưng sự cân bằng là bạn phải duy trì một trình phân tích cú pháp.

+10

Tôi muốn duy trì một trình phân tích cú pháp, cá nhân hơn là duy trì các mẫu C++ lồng nhau. –

+0

Bạn không cần một trình phân tích cú pháp. Sử dụng JetBrains Meta Programming System. Bạn có thể định nghĩa một ngôn ngữ, một trình soạn thảo và trình tạo mã. Bạn không cần một trình phân tích cú pháp nào cả bởi vì bạn đang chỉnh sửa trực tiếp cây cú pháp. Và nó không phải là một quảng cáo, chương trình này là FOSS. – naeron84

13

Tôi đã sử dụng nó trong các vòng bên trong mã đồ họa của trò chơi, nơi bạn muốn có một số mức độ trừu tượng và mô đun nhưng không thể trả chi phí của các chi nhánh hoặc cuộc gọi ảo. Nói chung nó là một giải pháp tốt hơn so với sự gia tăng của các hàm đặc biệt viết tay.

1

Có, tôi chủ yếu làm một số việc giống như gõ vịt khi tôi đang gói API cũ trong giao diện C++ hiện đại hơn.

2

Tôi chưa sử dụng nó trong mã sản xuất.

Tại sao?

  1. Chúng ta phải hỗ trợ hơn 6 nền tảng với mẹ đẻnền tảng trình biên dịch. Đó là đủ cứng để sử dụng STL trong môi trường này, hãy để các kỹ thuật mẫu hiện đại hiện đại.
  2. Nhà phát triển dường như không theo kịp tiến trình C++ nữa. Chúng tôi sử dụng C++ khi cần. Chúng tôi có mã kế thừa với thiết kế cũ. Mã mới là được thực hiện bằng một thứ khác, ví dụ: Java, Javascript, Flash.
+4

Đáng buồn thay, đây là trường hợp của chúng tôi. – Motti

-4

Nhiều lập trình viên không sử dụng nhiều mẫu vì trình biên dịch kém hỗ trợ cho đến gần đây. Tuy nhiên, trong khi các mẫu đã có rất nhiều vấn đề trong pas, các trình biên dịch mới hơn có hỗ trợ tốt hơn nhiều. Tôi viết mã mà đã làm việc với GCC trên Mac và Linux cũng như Microsoft Visual C++ và nó chỉ với GCC 4 và VC++ 2005 rằng các trình biên dịch đã hỗ trợ các tiêu chuẩn thực sự tốt.

Lập trình chung thông qua mẫu không phải là thứ bạn cần mọi lúc nhưng chắc chắn là một mã hữu ích có trong hộp công cụ của bạn.

Các lớp chứa ví dụ rõ ràng nhưng các mẫu cũng hữu ích cho nhiều thứ khác. Hai ví dụ từ công việc của tôi là:

  • con trỏ thông minh (ví dụ tham khảo-tính, copy-on-write, vv)
  • lớp hỗ trợ Math như Ma trận, vectơ, splines, vv mà cần phải hỗ trợ nhiều loại dữ liệu khác nhau và vẫn hiệu quả.
+2

Câu hỏi đặt ra là về lập trình mẫu * meta *, không phải các mẫu cũ đơn giản thường được sử dụng nhiều hơn. – Motti

11

Mẫu siêu lập trình mẫu và mẫu biểu hiện đang trở nên phổ biến hơn trong cộng đồng khoa học như là các phương pháp tối ưu hóa sẽ giảm bớt một số nỗ lực tính toán lên trình biên dịch trong khi duy trì một số trừu tượng. Mã kết quả là lớn hơn và ít có thể đọc được, nhưng tôi đã sử dụng các kỹ thuật này để tăng tốc các thư viện đại số tuyến tính và các phương pháp cầu phương trong thư viện FEM.

Để đọc ứng dụng cụ thể, Todd Veldhuizen là tên tuổi lớn trong lĩnh vực này. Một cuốn sách phổ biến là C++ and Object Oriented Numeric Computing for Scientists and Engineers bởi Daoqi Yang.

+2

Vâng, theo mục lục, sách của D. Yang chứa 7 trang tài liệu trên expr. các mẫu và lập trình meta mẫu. Phần còn lại có vẻ là một cuốn sách giáo khoa tổng quát 101, với một vài ví dụ với các phương pháp số. Không có gì sai với điều đó, tất nhiên. – janneb

+0

Đủ công bằng. Để tham khảo đầy đủ hơn, tôi sẽ đi với cuốn sách Alexandrescu. Các tài liệu tham khảo tôi trích dẫn cụ thể cho các ứng dụng máy tính khoa học và có thể bị giới hạn bởi kiến ​​thức của tôi về văn học. Cuốn sách [Barton/Nackman] (http://www.amazon.com/Scientific-Engineering-Introduction-Advanced-Techniques/dp/0201533936) cũng có một lượng nhỏ tài liệu. –

6

Hầu hết các lập trình viên sử dụng lập trình meta mẫu sử dụng nó gián tiếp, thông qua các thư viện như tăng cường. Họ thậm chí không biết những gì đang xảy ra đằng sau hậu trường, chỉ rằng nó làm cho cú pháp của các hoạt động nhất định dễ dàng hơn nhiều.

-1

Đừng làm vậy. Lý do đằng sau đó là như sau: theo bản chất của siêu lập trình mẫu, nếu một phần nào đó của logic của bạn được thực hiện tại thời gian biên dịch, mọi logic mà nó phụ thuộc vào cũng phải được thực hiện tại thời gian biên dịch. Một khi bạn bắt đầu nó, làm một phần của logic của bạn tại thời gian biên dịch, không có trở lại. Quả cầu tuyết sẽ tiếp tục lăn và không có cách nào để ngăn chặn nó.

Ví dụ: bạn không thể lặp lại các thành phần của tăng :: tuple <>, vì bạn chỉ có thể truy cập chúng vào thời gian biên dịch. Bạn phải sử dụng lập trình meta mẫu để đạt được điều C++ dễ dàng và đơn giản, và luôn là xảy ra khi người dùng C++ không đủ cẩn thận để không di chuyển quá nhiều thứ để biên dịch. Đôi khi rất khó để thấy khi nào việc sử dụng logic compiletime nhất định sẽ trở thành vấn đề, và đôi khi các lập trình viên sẵn sàng thử và kiểm tra những gì họ đã đọc trong Alexandrescu. Trong mọi trường hợp, đây là một ý tưởng rất tồi trong quan điểm của tôi.

+3

mpl :: for_each, boost.fusion, thông minh cons chuyên môn hóa tất cả cho phép khá dễ dàng cầu nối từ biên dịch để chạy thời gian v – KitsuneYMG

+0

Vâng, nó không phải là khó để quyết định một giới hạn mà bạn muốn vượt qua từ biên dịch-thời gian để chạy- lập trình thời gian. Rõ ràng, không phải tất cả các mã sử dụng một mẫu cần phải được thực hiện bằng cách sử dụng lập trình mẫu. Và thông thường, bạn không có nhiều cấp độ giữa mã chung chung có thể tái sử dụng và mã ứng dụng cụ thể. – Phil1970

7

Tôi sử dụng lập trình meta mẫu tất cả thời gian, nhưng trong D, không phải C++. C++'s template metalanguage ban đầu được thiết kế cho parametrization loại đơn giản và trở thành một kim loại hoàn chỉnh Turing gần như là do tai nạn. Do đó, một tarpit Turing chỉ có Andrei Alexandrescu, không chỉ là những người chết, có thể sử dụng. Mặt khác, mặt cắt mẫu của D được thiết kế để lập trình siêu lập trình ngoài parametrization loại đơn giản. Andrei Alexandrescu seems to love it, nhưng những người khác thực sự có thể hiểu các mẫu D của anh ấy. Nó cũng đủ mạnh để ai đó viết một compile-time raytracer trong đó như là một bằng chứng về khái niệm.

Tôi đoán metaprogram hữu ích/không tầm thường nhất mà tôi từng viết trong D là mẫu hàm, cho kiểu cấu trúc làm tham số mẫu và danh sách tên tiêu đề cột theo thứ tự tương ứng với khai báo biến trong struct như một tham số thời gian chạy, sẽ đọc trong một tệp CSV và trả về một mảng các cấu trúc, một cho mỗi hàng, với mỗi trường struct tương ứng với một cột. Tất cả các chuyển đổi kiểu (chuỗi thành float, int, v.v.) được thực hiện tự động, dựa trên các kiểu của các trường mẫu.

Một cách hay khác, mà chủ yếu là hoạt động, nhưng vẫn không xử lý đúng một vài trường hợp, là mẫu chức năng sao chép sâu xử lý cấu trúc, lớp và mảng đúng cách.Nó chỉ sử dụng sự phản xạ/nội suy thời gian biên dịch, để nó có thể làm việc với các cấu trúc, không giống như các lớp đầy đủ, không có sự tương phản thời gian/sự chú ý nội suy trong D vì chúng được cho là nhẹ.

+4

Thật hữu ích khi biết về D, nhưng tôi nghĩ câu hỏi là về C++, chứ không phải D. –

+1

Bất kể điều gì là hữu ích khi biết bạn có thể làm gì với metaprogramming khi bạn không phải là một guru để hiểu nó :) – shambulator

+0

Dường như liên kết tới vạch dấu bị hỏng: ( – Manu343726

20

tôi đã tìm thấy chính sách, mô tả trong Modern C++ Thiết kế, thực sự hữu ích trong hai tình huống:

  1. Khi tôi đang phát triển một thành phần mà tôi mong đợi sẽ được tái sử dụng, nhưng theo một cách hơi khác nhau. Đề nghị của Alexandrescu về việc sử dụng một chính sách để phản ánh một thiết kế phù hợp ở đây - nó giúp tôi có được những câu hỏi quá khứ như "Tôi có thể làm điều này với một chủ đề nền, nhưng nếu ai đó muốn làm điều đó trong lát thời gian thì sao?" Ok, tôi chỉ viết lớp của tôi để chấp nhận một ConcurrencyPolicy và thực hiện một trong những tôi cần vào lúc này. Sau đó, ít nhất tôi biết người đứng sau tôi có thể viết và cắm vào một chính sách mới khi họ cần nó, mà không cần phải hoàn toàn làm lại thiết kế của tôi. Caveat: Tôi phải cai trị bản thân mình trong đôi khi hoặc điều này có thể mất kiểm soát - hãy nhớ nguyên tắc YAGNI!

  2. Khi tôi đang cố gắng tái cấu trúc một số khối mã tương tự thành một. Thông thường mã sẽ được sao chép và dán một chút bởi vì nó sẽ có quá nhiều nếu logic khác, hoặc vì các kiểu liên quan quá khác nhau. Tôi đã thấy rằng các chính sách thường cho phép một phiên bản phù hợp với tất cả mọi nơi mà logic truyền thống hoặc đa thừa kế sẽ không cho phép.

2

Gần 8 tháng sau khi yêu cầu này cuối cùng tôi đã sử dụng một số TMP, tôi sử dụng một TypeList các giao diện để thực hiện QueryInterface trong một lớp cơ sở.

+0

Tôi đã muốn Chúng ta có rất nhiều mã di sản được bao bọc như các đối tượng COM để nó có thể được truy cập từ C#, nhưng không ai muốn làm việc trên nó hoặc mở rộng nó vì bản mẫu COM là Tôi cảm thấy chắc chắn metaprogramming mẫu có thể thực sự giúp đỡ, nhưng lập trình mẫu đơn giản không phải là đến nó vì cách thức quy tắc COM khác với những người C++ –

2

Tôi sử dụng nó với tăng :: statechart cho statemachines lớn.

+2

Bạn nên thử tăng sắp tới: msm - máy trạng thái meta (hy vọng trong Đó là một khung máy nhà nước entrire dựa trên metaprogramming và tuân thủ UML2 của nó. Chúng tôi đã sử dụng nó cho một vài dự án và nó chỉ tuyệt vời, ngược lại, có một thời gian biên dịch dài ... – fmuecke

+1

Vì vậy, nó khác nhau như thế nào trong các tính năng từ sc? Các khái niệm uml duy nhất sc thiếu là tràn và tham gia, đó là dễ dàng để thi đua. – KitsuneYMG

+0

@fmuecke Chỉ cần cập nhật. Tôi nhìn vào msm bây giờ rằng nó đang tăng cường thích hợp. Đó là không có cách nào thay thế cho statechart vì nó dường như thiếu bất kỳ loại hệ thống phân cấp nào. MSM có vẻ là một sơ đồ chuyển trạng thái, trong đó statechart giống như một statechart từ stateflow/simulink. – KitsuneYMG

4

Tôi đã sử dụng nó một chút với mã DSP, đặc biệt là FFT, bộ đệm tròn kích thước cố định, biến đổi hadamard và các loại tương tự.

9

Lập trình meta mẫu là một kỹ thuật tuyệt vời và quyền lực khi viết C++ thư viện. Tôi đã sử dụng nó một vài lần trong các giải pháp tùy chỉnh, nhưng thường là một giải pháp C++ kiểu cũ ít thanh lịch hơn thì dễ dàng hơn trong việc xem xét mã và dễ bảo trì hơn cho người dùng khác.

Tuy nhiên, tôi đã có rất nhiều mileage trong lập trình meta mẫu khi viết các thành phần/thư viện có thể tái sử dụng. Tôi không nói bất cứ điều gì là lớn một số công cụ của Boost chỉ là thành phần nhỏ sẽ được tái sử dụng thường xuyên.

Tôi đã sử dụng TMP cho một hệ thống đơn lẻ nơi người dùng có thể chỉ định loại đơn họ muốn. Giao diện rất cơ bản. Bên dưới nó được hỗ trợ bởi TMP nặng.

template< typename T > 
T& singleton(); 

template< typename T > 
T& zombie_singleton(); 

template< typename T > 
T& phoenix_singleton(); 

Một cách sử dụng thành công khác là đơn giản hóa lớp IPC của chúng tôi. Nó được xây dựng bằng cách sử dụng phong cách OO cổ điển. Mỗi thông điệp cần phải lấy được từ một lớp cơ sở trừu tượng và ghi đè lên một số phương thức tuần tự hóa. Không có gì quá khắc nghiệt, nhưng nó tạo ra rất nhiều mã tấm nồi hơi.

Chúng tôi đã ném một số TMP vào đó và tự động tạo ra tất cả mã cho trường hợp thông điệp đơn giản chỉ chứa dữ liệu POD. Các tin nhắn TMP vẫn sử dụng phần phụ trợ OO nhưng chúng giảm khối lượng mã tấm nồi hơi. TMP cũng được sử dụng để tạo ra vistor tin nhắn. Theo thời gian, tất cả thư của chúng tôi đã di chuyển sang phương thức TMP. Nó dễ dàng hơn và ít mã hơn để xây dựng một cấu trúc POD đơn giản chỉ để truyền thông điệp và thêm vài dòng (có thể 3) cần thiết để có TMP tạo ra các lớp hơn là lấy một thông báo mới để gửi một lớp thông thường trên IPC khuôn khổ.

4

Đối với những người quen thuộc với Thư viện Oracle Template (OTL), đẩy mạnh :: bất kỳ và Loki thư viện (một trong những mô tả trong Modern C++ Thiết kế) đây là bằng chứng của khái niệm đang TMP cho phép bạn lưu trữ một dãy otl_stream trong vector<boost::any> chứa và truy cập dữ liệu theo số cột. Và 'Có', tôi sẽ kết hợp nó trong mã sản xuất.

#include <iostream> 
#include <vector> 
#include <string> 
#include <Loki/Typelist.h> 
#include <Loki/TypeTraits.h> 
#include <Loki/TypeManip.h> 
#include <boost/any.hpp> 
#define OTL_ORA10G_R2 
#define OTL_ORA_UTF8 
#include <otlv4.h> 

using namespace Loki; 

/* Auxiliary structs */ 
template <int T1, int T2> 
struct IsIntTemplateEqualsTo{ 
    static const int value = (T1 == T2); 
}; 

template <int T1> 
struct ZeroIntTemplateWorkaround{ 
    static const int value = (0 == T1? 1 : T1); 
}; 


/* Wrapper class for data row */ 
template <class TList> 
class T_DataRow; 


template <> 
class T_DataRow<NullType>{ 
protected: 
    std::vector<boost::any> _data; 
public: 
    void Populate(otl_stream&){}; 
}; 


/* Note the inheritance trick that enables to traverse Typelist */ 
template <class T, class U> 
class T_DataRow< Typelist<T, U> >:public T_DataRow<U>{ 
public: 
    void Populate(otl_stream& aInputStream){ 
     T value; 
     aInputStream >> value; 
     boost::any anyValue = value; 
     _data.push_back(anyValue); 

     T_DataRow<U>::Populate(aInputStream); 
    } 

    template <int TIdx> 
    /* return type */ 
    Select< 
     IsIntTemplateEqualsTo<TIdx, 0>::value, 
     typename T, 
     typename TL::TypeAt< 
      U, 
      ZeroIntTemplateWorkaround<TIdx>::value - 1 
     >::Result 
    >::Result 
    /* sig */ 
    GetValue(){ 
    /* body */ 
     return boost::any_cast< 
      Select< 
       IsIntTemplateEqualsTo<TIdx, 0>::value, 
       typename T, 
       typename TL::TypeAt< 
        U, 
        ZeroIntTemplateWorkaround<TIdx>::value - 1 
       >::Result 
      >::Result 
     >(_data[ TIdx ]); 
    } 
}; 


int main(int argc, char* argv[]) 
{ 
    db.rlogon("AMONRAWMS/[email protected]"); // connect to Oracle 
    std::cout<<"Connected to oracle DB"<<std::endl; 
    otl_stream o(1, "select * from blockstatuslist", db); 

    T_DataRow< TYPELIST_3(int, int, std::string)> c; 
    c.Populate(o); 
    typedef enum{ rcnum, id, name } e_fields; 
    /* After declaring enum you can actually acess columns by name */ 
    std::cout << c.GetValue<rcnum>() << std::endl; 
    std::cout << c.GetValue<id>() << std::endl; 
    std::cout << c.GetValue<name>() << std::endl; 
    return 0; 
}; 

Đối với những người không quen thuộc với các thư viện được đề cập.

Vấn đề với containter otl_stream OTL là rằng người ta có thể truy cập vào các cột dữ liệu chỉ trong thứ tự tuần tự bằng cách tuyên bố biến của loại thích hợp và áp dụng các operator >> để otl_stream đối tượng theo cách sau:

otl_stream o(1, "select * from blockstatuslist", db); 
int rcnum; 
int id; 
std::string name; 
o >> rcnum >> id >> name; 

Nó không phải lúc nào cũng thuận . Cách giải quyết là viết một số lớp bao bọc và điền nó với dữ liệu từ otl_stream. Mong muốn là để có thể khai báo danh sách các loại cột và sau đó:

  • có loại T của cột
  • khai báo biến kiểu đó
  • áp dụng olt_stream::operator >>(T&)
  • cửa hàng kết quả (trong vector của boost :: có)
  • có loại của cột tiếp theo và lặp lại cho đến khi tất cả các cột được xử lý

Bạn có thể làm al l này với sự giúp đỡ của Loki Typelist cấu trúc, mẫu chuyên môn và kế thừa.

Với sự trợ giúp của cấu trúc thư viện của Loki, bạn cũng có thể tạo ra các hàm GetValue trả về các giá trị của loại thích hợp suy ra từ số cột (thực tế là số kiểu trong Typelist).

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