Templates so với macro tiền xử lý
Một câu hỏi có thể nảy sinh tại một thời điểm nào đó, liệu có thể sử dụng thay thế macro để tạo mã không? Thực ra điều này là có thể. Ví dụ, tập hợp các hàm Max
có thể dễ dàng được biểu diễn dưới dạng một macro:
#define MAX(V1,V2) ((V1) > (V2) ? (V1) : (V2))
Tuy nhiên, macro có khả năng hạn chế hơn (chỉ đơn thuần là thay thế văn bản) và do đó chúng chỉ được sử dụng trong các trường hợp đơn giản (như ví dụ trên).
Khi so sánh macro và mẫu, cần lưu ý những khác biệt sau.
Macro được "mở rộng" và thay thế trong văn bản nguồn bởi tiền xử lý trước khi quá trình biên dịch bắt đầu. Đồng thời, không có thông tin về kiểu của các tham số và ngữ cảnh mà nội dung của macro được thay thế vào. Đặc biệt, macro MAX không thể cung cấp kiểm tra xem các kiểu của tham số V1 và V2 có giống nhau không, cũng như toán tử so sánh >
có được định nghĩa cho chúng hay không. Ngoài ra, nếu một biến có tên MAX xuất hiện trong văn bản chương trình, tiền xử lý sẽ cố gắng thay thế "lời gọi" của macro MAX vào vị trí đó và sẽ "không hài lòng" với việc thiếu đối số. Tệ hơn nữa, các thay thế này bỏ qua không gian tên hoặc lớp mà token MAX được tìm thấy – về cơ bản, bất kỳ cái nào cũng được.
Không giống như macro, mẫu được trình biên dịch xử lý dựa trên các kiểu đối số cụ thể và nơi chúng được sử dụng, vì vậy chúng cung cấp kiểm tra tính tương thích kiểu (và khả năng áp dụng chung) cho tất cả các biểu thức trong mẫu, cũng như liên kết ngữ cảnh. Ví dụ, chúng ta có thể định nghĩa một phương thức mẫu trong một lớp cụ thể.
Một mẫu có cùng tên có thể được định nghĩa khác nhau cho các kiểu khác nhau nếu cần, trong khi một macro với một tên nhất định luôn được thay thế bằng cùng một "triển khai". Ví dụ, trong trường hợp của hàm như MAX, chúng ta có thể định nghĩa một so sánh không phân biệt chữ hoa chữ thường cho chuỗi.
Các lỗi biên dịch do vấn đề trong macro rất khó chẩn đoán, đặc biệt nếu macro gồm nhiều dòng, vì dòng có vấn đề với "lời gọi" của macro được đánh dấu "nguyên trạng", không có phiên bản văn bản mở rộng, như nó được chuyển từ tiền xử lý sang trình biên dịch.
Ngược lại, mẫu là các yếu tố của mã nguồn ở dạng sẵn sàng, như chúng đi vào trình biên dịch, và do đó bất kỳ lỗi nào trong chúng đều có số dòng cụ thể và vị trí trong dòng.
Macro có thể gây ra tác dụng phụ, điều mà chúng ta đã thảo luận trong phần Dạng #define như một hàm giả: nếu các đối số của macro MAX là biểu thức có tăng/giảm, thì chúng sẽ được thực thi hai lần.
Tuy nhiên, macro cũng có một số lợi thế. Macro có khả năng tạo ra bất kỳ văn bản nào, không chỉ các cấu trúc ngôn ngữ chính xác. Ví dụ, với một vài macro, bạn có thể mô phỏng lệnh switch
cho chuỗi (mặc dù cách tiếp cận này không được khuyến nghị).
Trong thư viện chuẩn, macro được sử dụng, đặc biệt, để tổ chức xử lý các sự kiện trên biểu đồ (xem MQL5/Include/Controls/Defines.mqh
: EVENT_MAP_BEGIN, EVENT_MAP_END, ON_EVENT, v.v.). Điều này sẽ không hoạt động trên mẫu, nhưng cách sắp xếp bản đồ sự kiện trên macro, tất nhiên, không phải là duy nhất và cũng không phải là cách tiện lợi nhất để gỡ lỗi. Việc gỡ lỗi từng bước (theo dòng) quá trình thực thi mã trong macro rất khó. Ngược lại, mẫu hỗ trợ gỡ lỗi đầy đủ.