Có phải tất cả đều sử dụng các mẫu trong siêu dữ liệu C ++?


8

Tôi đang cố gắng hiểu những gì siêu lập trình là chung và những gì trong C ++ nói riêng. Nếu tôi tìm kiếm siêu lập trình c ++, tôi có được hướng dẫn về siêu lập trình mẫu (TMP), nhưng không giải thích được nếu nó chỉ phân loại việc sử dụng cụ thể của mẫu hoặc tất cả các cách sử dụng mẫu.

Câu hỏi của tôi là nếu tất cả các cách sử dụng các mẫu trong C ++ được phân loại là siêu lập trình. Một lời giải thích về lý do tại sao nó hoặc không cũng sẽ hữu ích. Cảm ơn bạn.


1
So sánh với các macro CL và xem quy tắc thứ mười của Greensasta. vi.wikipedia.org/wiki/G Greensasta% 27s_tenth_rule
stark

1
TMP không phải là cách duy nhất để lập trình siêu dữ liệu. Người ta cũng có thể thực hiện siêu lập trình với các hàm macro (uhh) và constexpr . Constexpr có thể dễ thực hiện hơn TMP.
zett42

1
@ zett42 Tôi không chắc liệu việc chỉ thực thi mã trong thời gian biên dịch có phải được coi là "siêu lập trình" hay không. Bởi vì đó không phải là lập trình , mà là máy tính. Nó chỉ đơn thuần là chuyển việc thực thi từ thời gian chạy sang thời gian biên dịch. Metaprogramming trong C ++ khác với điều đó, bởi vì nó tạo mã (mẫu, macro).
Julian Schaub - litb

Câu trả lời:


2

Câu hỏi của tôi là nếu tất cả các cách sử dụng các mẫu trong C ++ được phân loại là siêu lập trình.

Không.

Không phải tất cả các cách sử dụng mẫu, trong C ++, đều là siêu lập trình.

Rõ ràng đó là một câu hỏi về định nghĩa nhưng, trong C ++, "siêu lập trình" đồng nghĩa với "tính toán thời gian biên dịch".

Vì vậy, với các mẫu chúng tôi thực hiện siêu lập trình (cụ thể là siêu lập trình mẫu) nhưng không phải tất cả các cách sử dụng mẫu đều là siêu lập trình.

Một ví dụ đơn giản

template <typename K, typename V>
void printKeyVal (K const & k, V const & v)
 { std::cout << k << ": " << v << std::endl; }

Phần trước printKeyVal()là một hàm mẫu in, thành đầu ra tiêu chuẩn (vì vậy thời gian chạy, không phải thời gian biên dịch), một vài giá trị chung.

Nó không thể chạy thời gian biên dịch vì vậy nó là "mẫu" nhưng không phải là "siêu lập trình".

Nói chung hơn: std::vectorlà một lớp mẫu sử dụng cấp phát bộ nhớ. Và cấp phát bộ nhớ (cho đến C ++ 17; có thể trong tương lai có thể khác) không thể được sử dụng trong mã thời gian biên dịch.

Vì vậy std::vector(trái với std::arrayđiều đó, có kích thước cố định, không sử dụng cấp phát bộ nhớ) là một tính năng mẫu không thể được sử dụng (khi việc sử dụng liên quan đến việc khởi tạo std::vectorđối tượng) để lập trình siêu dữ liệu.


Tuy nhiên, bất kỳ chức năng nào phụ thuộc vào mẫu, đều yêu cầu ít nhất một số siêu lập trình. Trong ví dụ của bạn, printKeyValnó được xác định trong thời gian biên dịch theo các đối số được tạo khuôn mẫu
Tên người dùng

Khi bạn lập trình, bạn viết mã. Bạn không "tính toán" mọi thứ. Vì vậy, tôi sẽ định nghĩa "siêu lập trình" là "viết mã để viết mã". Và đây là chính xác những gì mọi mẫu về. Tôi biết rằng siêu lập trình mẫu thường được sử dụng cho "tính toán thời gian biên dịch" -y, nhưng cá nhân tôi sẽ sử dụng một thuật ngữ khác cho điều đó (tôi chắc chắn rằng tôi đã không làm như vậy trong quá khứ, vì vậy xin lỗi).
Julian Schaub - litb

@ JohannesSchaub-litb - Đó là vấn đề về ngôn ngữ và định nghĩa (và tôi có thêm điểm chấp là tôi không biết tiếng Anh) và tôi đồng ý rằng một định nghĩa về "siêu lập trình" bao gồm tất cả các mẫu là có thể và cũng có thể hợp lý. Điều tôi nói là, trong cộng đồng C ++, thuật ngữ "siêu lập trình" được sử dụng với một ý nghĩa khác giao nhau nhưng không bao gồm tất cả các cách sử dụng mẫu. Có lẽ tôi sai ... có thể là một cuộc thăm dò thú vị.
max66

Có lẽ nó chỉ được gọi là "siêu lập trình" nếu mã của mẫu không phải là trùng lặp 1: 1 cho mỗi loại, bởi vì nếu trùng lặp 1: 1 thì mã mẫu hoàn toàn bị động và tất cả "lập trình meta" được trình biên dịch thực hiện . Nếu có một số chuyên môn hoặc tĩnh - nếu hoặc quá tải - gửi đi hoặc một cái gì đó, thì chính mã đó sẽ quyết định những gì sẽ được tạo ra. Điều này dường như là lập trường của D: tour.dlang.org/tour/en/gems/template-meta-programming
Johannes Schaub - litb

@SomeWittyUsername - Dường như với tôi rằng bạn đang sử dụng định nghĩa "siêu lập trình" rằng, hoàn toàn hợp pháp và cũng có thể hợp lý, khác với cộng đồng C ++, trên thực tế, sử dụng: nói một cách khó hiểu: "metaprogramming == biên dịch thời gian thực hiện ". Có lẽ tôi sai và cộng đồng sử dụng chủ yếu một định nghĩa bao gồm tất cả các mẫu sử dụng ... tôi có thể là một cuộc thăm dò thú vị, tôi cho rằng.
max66

1

TMP trong C ++ là gì?

Siêu lập trình mẫu (TMP) trong C ++ là một kỹ thuật để thể hiện và thực hiện các thuật toán tùy ý trong thời gian biên dịch bằng cách sử dụng các mẫu C ++. Nó thường được kích hoạt bằng cách sử dụng chuyên môn hóa mẫu để mô phỏng các nhánh có điều kiện và định nghĩa mẫu đệ quy để mô phỏng các vòng lặp. Ví dụ nổi tiếng nhất là tính toán giai thừa biên dịch:

template <unsigned int n>
struct factorial {
    // recursive definition to emulate a loop or a regular recursion
    enum { value = n * factorial<n - 1>::value };
};

// specialization that describes "break" condition for the recursion
template <>
struct factorial<0> { 
    enum { value = 1 };
};

trong đó sử dụng cả hai kỹ thuật nói trên.

Tuy nhiên, phổ biến hơn nhiều là việc sử dụng TMP để phát hiện và chuyển đổi loại thay vì tính toán số thực tế, ví dụ: một std::is_pointertiện ích tiêu chuẩn ( nguồn ):

// generic definition that emulates "false" conditional branch
template<class T>
struct is_pointer_helper : std::false_type {};

// a specialization that emulates "true" conditional branch
template<class T>
struct is_pointer_helper<T*> : std::true_type {};

template<class T>
struct is_pointer : is_pointer_helper< typename std::remove_cv<T>::type > {};

Hầu hết các tiện ích được cung cấp bởi tiêu đề type_traits tiêu chuẩn được triển khai bằng các kỹ thuật TMP.

Cho rằng các thuật toán TMP được thể hiện bằng định nghĩa kiểu, nó có giá trị đề cập rằng TMP là một hình thức lập trình khai báo trong đó logic của tính toán được thể hiện mà không cần dùng báo cáo dòng điều khiển rõ ràng ( if, else, for, vv ...).

Có phải tất cả việc sử dụng các mẫu C ++ là một siêu lập trình?

Câu trả lời ngắn gọn là: Không. Nếu các mẫu không được sử dụng để thể hiện thuật toán thời gian biên dịch thì đó không phải là siêu lập trình, đó là một chương trình chung .

Các mục tiêu chính cho việc giới thiệu các mẫu trong C ++ là để cho phép lập trình chung, đó là cho phép tái sử dụng các thuật toán tương tự ( find, copy, sort, vv ...) và cấu trúc dữ liệu ( vector, list, map, vv ...) cho bất kỳ loại, bao gồm user- xác định những cái, đáp ứng yêu cầu nhất định.

Trong thực tế, TMP trong C ++ được phát hiện một cách tình cờ và không phải là mục đích sử dụng của các mẫu.


Tóm lại: Siêu lập trình mẫu trong C ++ là việc sử dụng các mẫu để thể hiện thuật toán thời gian biên dịch, hầu hết (tất cả?) Các cách sử dụng khác của các mẫu C ++ là một dạng lập trình chung.


0

Tôi đang cố gắng hiểu những gì siêu lập trình nói chung và những gì nó có trong C ++ nói riêng

Bạn chưa nói những gì bạn hiểu bằng cách lập trình siêu hình nói chung , vì vậy câu trả lời của bạn không có điểm bắt đầu chung.

Tôi sẽ giả định định nghĩa wikipedia là đủ tốt cho việc này:

Metaprogramming là một kỹ thuật lập trình trong đó các chương trình máy tính có khả năng coi các chương trình khác là dữ liệu của chúng.

... có thể được sử dụng để di chuyển các tính toán từ thời gian chạy sang thời gian biên dịch, để tạo mã bằng cách sử dụng tính toán thời gian biên dịch ...

C ++ thường không cho phép tự sửa đổi mã, vì vậy tôi bỏ qua điều đó. Tôi cũng chọn không tính bộ tiền xử lý, vì thời gian biên dịch văn bản tại (hoặc được cho là ngay trước đó) thời gian biên dịch không giống như hoạt động trên ngữ nghĩa của chương trình.

Câu hỏi của tôi là nếu tất cả các cách sử dụng mẫu trong C ++ được phân loại là siêu lập trình

Không có nó không phải là.

Xem xét, để tham khảo:

#define MAX(a,b) ((a) > (b) ? (a) : (b))

đó là cách lỏng lẻo để viết một hàm chung (loại bất khả tri) maxmà không sử dụng các mẫu. Tôi đã nói rằng tôi không coi bộ tiền xử lý là siêu lập trình, nhưng trong mọi trường hợp, nó luôn tạo ra mã giống hệt nhau bất cứ khi nào nó được sử dụng.

Nó chỉ đơn giản là ủy thác phân tích mã đó, và lo lắng về các loại và liệu có a>bđược xác định cho trình biên dịch hay không, trong giai đoạn dịch sau . Không có gì ở đây hoạt động vào thời gian biên dịch để tạo mã kết quả khác nhau tùy thuộc vào ... bất cứ điều gì. Không có gì, tại thời gian biên dịch, được tính toán.

Bây giờ, chúng ta có thể so sánh phiên bản mẫu:

template <typename T>
T max(T a, T b) { return a > b ? a : b; }

Điều này không chỉ đơn giản là thực hiện một sự thay thế văn bản. Quá trình khởi tạo phức tạp hơn, các quy tắc tra cứu tên và quá tải có thể được xem xét và trong một số trường hợp, các khởi tạo khác nhau có thể không tương đương về mặt văn bản (ví dụ: một người có thể sử dụng bool ::operator< (T,T)và một bool T::operator<(T const&)hoặc bất cứ điều gì).

Tuy nhiên, ý nghĩa của mỗi khởi tạo là như nhau (giả sử các định nghĩa tương thích về operator<các loại khác nhau, v.v.) và không có gì được tính toán tại thời điểm biên dịch ngoài quy trình giải quyết các loại và tên thông thường của máy tính.

Bên cạnh đó, chắc chắn chương trình của bạn chứa các hướng dẫn để trình biên dịch nói cho nó biết phải làm gì , bởi vì đó là tất cả các chương trình.

Bây giờ, có những trường hợp cận biên như

template <unsigned N>
struct factorial() { enum { value = N * factorial<N-1>::value }; };

làm di chuyển một tính toán đến thời gian biên dịch (và trong trường hợp này một tổ chức phi chấm dứt một kể từ khi tôi không thể bị làm phiền để viết trường hợp thiết bị đầu cuối), nhưng được cho là không lập trình meta.

Mặc dù định nghĩa Wikipedia đã đề cập đến việc tính toán chuyển sang thời gian biên dịch, đây chỉ là một tính toán giá trị - nó không đưa ra quyết định về thời gian biên dịch về cấu trúc hoặc ngữ nghĩa của mã của bạn.


-1

Khi viết các hàm C ++ bằng các mẫu, bạn đang viết "hướng dẫn" cho trình biên dịch để cho nó biết phải làm gì khi gặp các lệnh gọi của hàm. Theo nghĩa này, bạn không trực tiếp viết mã, do đó chúng tôi gọi đó là lập trình meta.

Vì vậy, có, mọi mã C ++ liên quan đến các mẫu được coi là lập trình meta

Lưu ý rằng chỉ có các phần xác định các hàm hoặc lớp mẫu là lập trình meta. Các hàm và lớp thông thường được phân loại là C ++ thông thường!


1
Khi tôi gõ "cp a.txt b.txt" trong Bash, đây không phải là lập trình mặc dù tôi đang sử dụng một môi trường lập trình đầy đủ. Tương tự như vậy khi tôi sử dụng, std::vectortôi hướng dẫn một trình biên dịch để tạo ra một chương trình (vì vậy nó thực sự là meta) nhưng bản thân lệnh đó hầu như không phải là một chương trình. Hầu hết mọi người không xem xét việc sử dụng macro "siêu lập trình".
n. 'đại từ' m.

1
Bạn trả lời đơn giản là sai! Xin vui lòng đọc các câu trả lời khác được đưa ra trong chủ đề này để hiểu cơ bản về ý nghĩa của MTP!
Klaus

1
Bất cứ khi nào bạn viết C ++ mà không có mẫu, bạn sẽ viết hướng dẫn cho trình biên dịch. Vì vậy, thực tế là các mẫu cho trình biên dịch biết phải làm gì, không thể đủ để phân biệt lập trình với siêu lập trình
Vô dụng

1
@ JohannesSchaub-litb Trong ngữ cảnh của C ++, thuật ngữ "siêu lập trình" có một ý nghĩa cụ thể khác với ý nghĩa chung của nó . IIRC ban đầu đề cập đến tính năng C ++ được phát hiện do A.Alexandrescu đưa ra trong cuốn sách Modern C ++ Design . Việc sử dụng cổ điển của mẫu trong C ++ không phải là siêu lập trình (trừ khi bạn sử dụng siêu lập trình thuật ngữ không C ++).
YSC

1
Từ câu hỏi của OP: "Tôi đang cố gắng hiểu siêu lập trình là gì và nói chung trong C ++ là gì" . Vì vậy, tôi đoán góc của bạn là tốt và sẽ tạo thành một câu trả lời tuyệt vời. Nhưng cái này thì không. -1
YSC
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.