Có tài nguyên nào về cách xác định các vấn đề có thể giải quyết tốt nhất với các mẫu không?


8

Tôi quyết định nâng cao kiến ​​thức của mình trong lập trình meta mẫu. Tôi biết cú pháp và quy tắc và đã chơi với vô số ví dụ từ các tài nguyên trực tuyến.

Tôi hiểu các mẫu có thể mạnh đến mức nào và tối ưu hóa thời gian biên dịch mà chúng có thể cung cấp nhưng tôi vẫn không thể "nghĩ theo mẫu", tôi dường như không thể tự mình biết nếu một vấn đề nào đó có thể được giải quyết tốt nhất với các mẫu và nếu có thể, Làm thế nào để thích ứng vấn đề đó với các mẫu.

Có một số loại tài nguyên hoặc sách trực tuyến dạy cách xác định các vấn đề có thể được giải quyết tốt nhất với các mẫu và cách điều chỉnh vấn đề đó?


5
Nếu tất cả những gì bạn có là một cái búa, mọi thứ trông giống như một cái đinh ;-) Đừng cố gắng quá nhiều về việc nghĩ về việc sử dụng các mẫu cho tất cả và mọi thứ, ít nhất, không, nếu bạn sẽ không thiết kế phiên bản tiếp theo của tiêu chuẩn C ++ thư viện.
Doc Brown

bạn nói đúng, tôi sẽ không xem mã sản xuất và cố gắng phù hợp với TMP ở mọi nơi heh: p này chỉ dành cho học tập cá nhân, bởi vì tôi biết họ có thể mạnh đến mức nào và tôi yêu cách một số lập trình viên C ++ tuyệt vời (như STL làm việc trên MS) có thể áp dụng TMP rất nhanh cho một vấn đề nhất định và ir trông rất tuyệt vời. STL có một vài video trên channel9 thực sự khiến tôi ấn tượng về TMP, đó là lý do tại sao tôi muốn tìm hiểu thêm.
nhựa

Câu trả lời:


8

Sách:

Thiết kế C ++ hiện đại

Lập trình siêu mẫu C ++

Làm quen với đệ quy và lập trình chức năng là một điểm cộng rất lớn, vì đó là điều mà rất nhiều tmp liên quan. Nó hoàn thành đầy đủ và về cơ bản mọi thứ đều có thể, mặc dù thông thường, nó tập trung vào việc áp dụng các hàm thuần túy cho các hằng số hoặc tạo các loại từ các loại khác.

Cảnh báo: tmp là một con quái vật xấu xí biến mã đẹp thành spaghetti. Bạn càng sử dụng nó, bạn sẽ càng ít thích C ++. Đó là một điều xấu xa.


1
+1 cho nhóm tmp là một con quái vật xấu xí. C ++ giỏi một số thứ, giống như bất kỳ ngôn ngữ nào; nhưng siêu lập trình không phải là một trong số đó.
Jon Purdy

"Thiết kế C ++ hiện đại" là một kiểu cổ điển, nhưng IIRC nói nhiều hơn về việc triển khai mọi thứ bằng cách sử dụng các thủ thuật mẫu thông minh hơn là quyết định những gì nên được thực hiện như một mẫu. Không. 1 nguyên tắc cho điều đó có lẽ là "không" - những lý do phổ biến nhất để cần một mẫu đã được thư viện chuẩn (đặc biệt là C ++ 11), Boost và các thư viện đã tồn tại khác, do đó cần phải cuộn riêng không thực sự là một điều hàng ngày.
Steve314

Siêu mẫu C ++ Metaprogramming chỉ là hướng dẫn sử dụng của một phần của boost. Không dạy bạn nhiều về việc chọn ứng dụng phù hợp cũng như về cách thực hiện những điều tương tự trong C ++.
AProgrammer

6

Tìm hiểu Haskell hoặc một số ngôn ngữ chức năng thuần túy khác (Lisp, Scheme, OCaml để đặt tên cho một số ít, bạn có thể tìm thêm trên Wikipedia ).

Xem xét Haskell, bạn có thể tìm thêm thông tin về các cơ sở siêu lập trình của nó ở đây .

Lập trình mẫu tuân theo nhiều quy tắc thực sự giống nhau.


1
Lưu ý rằng Haskell có hệ thống tạo khuôn mẫu riêng: Mẫu Haskell.

2
@MattFenwick: Vâng. Và nó vẫn là Haskell, không giống như các mẫu c ++. :)
Macke

tôi chưa làm việc với một ngôn ngữ chức năng kể từ khi học ở trường đại học. không phải là tôi không thích nó, nó chỉ không bao giờ có cơ hội làm việc và nếu tôi phải dành thời gian rảnh để viết mã hoặc học thêm, tôi chỉ học một cái gì đó khác (như TMP!) :)
sap

@sap: Chà, bạn cần vào cùng một chế độ suy nghĩ ...
Macke

@sap: Thật ra, Scheme có thể là một ngôn ngữ tuyệt vời để làm quen với việc lập trình siêu dữ liệu thời gian biên dịch. Hệ thống macro của nó cực kỳ có khả năng và thanh lịch trong khi đạt được hiệu ứng tương tự như các mẫu của C ++ (tôi nghĩ vậy. Tôi đã không sử dụng C ++ quá nhiều).
Tikhon Jelvis

2

Chỉ vì bạn có thể làm gì đó với các mẫu không có nghĩa là bạn nên làm. Nói một cách thực tế trừ khi bạn đang thiết kế, bạn nghĩ rằng đây là một công việc tuyệt vời cho các mẫu, có lẽ tốt hơn là không sử dụng chúng. nếu bạn nghĩ quá nhiều trong các mẫu, bạn chỉ cần tạo mã trừu tượng điên rồ, tệ như một hàm khổng lồ.


cảm ơn vì câu trả lời, vâng tôi hiểu điều đó, tôi chỉ muốn tìm hiểu :)
sap

Tôi đông y vơi nhưng điêu trên. Trong các trường hợp tôi đã sử dụng các mẫu, nó thường là kết quả của việc tái cấu trúc mã hiện có. Khi bạn đang sử dụng mã gốc của mình theo những cách mới, mẫu sẽ xuất hiện rõ ràng hơn như là một cải tiến so với bản gốc. Thật khó để biết một mẫu có hữu ích khi thực hiện thiết kế trước khi có các trường hợp sử dụng đã biết hay không.
Sam Goldberg

2

Hãy nhớ rằng các mẫu là giải pháp tốt nhất là rất hiếm. Tôi chỉ xác định một lần trong 5 năm qua và các đồng nghiệp đã xem xét mã đó chưa bao giờ thực hiện. Các trường hợp mà các mẫu có nhiều ý nghĩa hầu hết đã được thực hiện trong các thư viện tiêu chuẩn.

Đối với lập trình chung, điều cần chú ý là bạn đang sao chép và dán các hàm để chỉ thực hiện các thay đổi nhỏ, như trong hằng hoặc loại và không thể tìm ra cách sạch để sử dụng một cái gì đó như thừa kế hoặc tham số hàm để tránh lặp lại bản thân bạn.

Một cách khá phổ biến được sử dụng là an toàn kiểu, nếu bạn có các kiểu hành xử giống nhau, nhưng vì bất kỳ lý do gì bạn không muốn chúng vô tình trộn lẫn.

Để tính toán thời gian biên dịch bằng cách sử dụng các mẫu, điều cần chú ý là các tính toán sử dụng nhiều tài nguyên, trong đó tất cả các đầu vào của nó được biết đến tại thời gian biên dịch, nhưng ở đó các đầu vào không đổi khác nhau được sử dụng ở các vị trí khác nhau trong toàn bộ mã. Tuy nhiên, hãy nhớ rằng điều này sẽ làm chậm quá trình biên dịch của bạn mỗi lần, vì vậy, tốt hơn là chỉ nên mã cứng các kết quả theo cách thủ công, nếu chúng không thay đổi rất thường xuyên.

Một số người ủng hộ sử dụng các mẫu để tối ưu hóa vi mô như tránh tra cứu bảng ảo bằng cách sử dụng đa hình tĩnh hoặc để không kiểm soát vòng lặp, nhưng theo tôi, độ phức tạp thường vượt trội so với mức tăng hiệu suất trừ khi mã của bạn rất quan trọng về hiệu năng.


cảm ơn bạn rất nhiều vì câu trả lời, tôi sẽ ghi nhớ những điểm đó Tôi biết rằng tôi không thể sử dụng nó cho mọi thứ (như ai đó đã nói trước đây, tôi không thể bắt đầu xem mọi thứ là "cái đinh") và nếu tôi hiểu chính xác TMP vượt trội trong việc phát triển thư viện (toàn bộ C ++), tôi chỉ làm điều này để học và KHÔNG để áp dụng nó trong mọi mã sản xuất mà tôi tạo ra từ bây giờ. và wow chỉ một lần trong 5 năm? Tôi đoán điều đó cho thấy TMP hiếm có thể THỰC SỰ cải thiện mã như thế nào.
sap

2

Về cơ bản, có một số lý do tốt để sử dụng các mẫu:

  1. Bạn có một chức năng hoặc một lớp có cùng chức năng cho các loại khác nhau. Ví dụ điển hình về việc sử dụng các mẫu tốt là thư viện boost
  2. bạn muốn sử dụng đa hình tĩnh và nhận lỗi biên dịch, thay vì lỗi thời gian chạy
  3. bạn muốn có một hành vi cụ thể tùy thuộc vào một số tham số tĩnh. Ví dụ, boost :: type_traits cung cấp các ví dụ rất tốt.

cảm ơn! ive sử dụng đặc điểm loại trước đây, công cụ thực sự mát mẻ! enable_if cũng là một đặc điểm loại? hay chỉ là một "điều kiện" SFINAE? bởi vì tôi đã sử dụng nó trước đây (về đánh giá mã) và nó có vẻ rất mạnh mẽ nhưng tôi không áp dụng nó cho các vấn đề khác nhau.
nhựa

@sap Đây là một đặc điểm loại, có thể được thực hiện bằng SFINAE.
BЈовић

1

Bạn chắc chắn nên xem xét các mẫu trong C ++! Điều này sẽ giúp bạn hiểu rất nhiều chủ đề như Mẫu thiết kế và Lập trình chung. Đừng so sánh chúng với những gì các ngôn ngữ khác cung cấp cho bạn. Chính xác, bạn nên sử dụng các mẫu đặc biệt trong các tình huống sau:

  1. Tổng quát hóa & tái sử dụng mã
  2. Uyển chuyển
  3. Hạn chế về thời gian và ngân sách
  4. Thiếu chuyên môn cho một nhiệm vụ nhất định

Đây là một tài nguyên trực tuyến tốt cho bạn: http://en.wikipedia.org/wiki/Generic_programming#Temsheet_in_C.2B.2B


tôi biết những gì họ có thể được sử dụng không chỉ là làm thế nào để áp dụng kiến ​​thức đó vào các vấn đề được đưa ra, mà vẫn là một lời cảm ơn rất hay đọc :)
sap

1

Một chỉ báo đơn giản về thời điểm một mẫu sẽ cải thiện mã của bạn, là khi bạn thấy rằng mã của bạn thường xuyên yêu cầu bạn chuyển một đối tượng sang một loại khác. Một ví dụ tôi tìm thấy trong mã Java của riêng mình, điều này đã kích hoạt tôi chuyển đổi chữ ký phương thức hiện có thành một mẫu:

    public MsgBase getLastSentMessage(Class<? extends MsgBase> msgBaseClass)

Mã khách hàng của tôi luôn trông như thế này:

    OrderResponse response = (OrderResponse) getLastSentMessage(OrderResponse.class);

và bất cứ khi nào tôi sử dụng phương thức đó, tôi phải đưa kết quả vào lớp con chính xác của loại MsgBase. Chữ ký phương thức được cải tiến là:

    public <T extends MsgBase> T getLastSentMessage(Class<T> clazz)

Bây giờ mã khách hàng là:

     OrderResponse response = getLastSentMessage(OrderResponse.class);

Vì vậy, để tóm tắt, nếu bạn thấy mình thực hiện nhiều thao tác đúc có vẻ không cần thiết, bạn có thể có một trường hợp tốt trong đó một mẫu sẽ dọn sạch mã của bạn.

Cập nhật: một cách tốt hơn để khái quát hóa tuyên bố trên:

Khi lớp nguồn của bạn sẽ được sử dụng bởi các đối tượng thuộc nhiều loại khác nhau và lớp nguồn có thể tương tác với các loại đó ở mức cao hơn (trừu tượng hơn), nhưng các lớp khách của bạn muốn tương tác với các kiểu con cụ thể, đó là trường hợp sử dụng các mẫu . (Các lớp Container / List là ví dụ nổi tiếng).


Điều này rất thú vị và tôi chưa bao giờ nghĩ đến việc áp dụng TMP như thế, chỉ đi để chứng tỏ rằng tôi thực sự cần phải học nó tốt hơn và thực hành nhiều hơn.
nhựa

Tôi vẫn đang cố gắng tìm ra số phiếu giảm ở đây. Tôi đã trả lời câu hỏi trực tiếp và cung cấp một ví dụ cụ thể về thời điểm Mẫu phát sinh từ việc tái cấu trúc. Vậy điều gì đã sai?
Sam Goldberg

0

Mới hôm nay, tôi đã sử dụng các mẫu để triển khai Máy trạng thái hữu hạn để lex một số đầu vào. Các mẫu biểu thức là các công cụ cực kỳ mạnh mẽ để thực hiện các khái niệm mã như thế - chúng chạy như C ++ được tối ưu hóa bằng tay và rất nhanh, nhưng rất chung chung và rất dễ viết.

Nói chung, các mẫu có ý nghĩa nhất khi thực hiện các thuật toán chung. Nếu bạn không thực hiện một thuật toán chung, chúng sẽ không có ý nghĩa nhiều như vậy.


0

Việc sử dụng phổ biến nhất của các mẫu như sau:

std::vector<int> vec;
std::map<int, float> mymap;

Sau đó, ví dụ phổ biến tiếp theo là:

template<class T>
class MyArray {
public:
   virtual T get(int i) const=0;
};

Cùng với cách sử dụng này:

class ArrayImpl : public MyArray<float> {
public:
     float get(int i) const { }
};

Điều đó cho thấy một phần quan trọng của các mẫu, đó là sự thay thế kiểu - T được thay thế bằng kiểu float ở cả hai nơi được sử dụng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.