Khuôn mẫu hàm
Các khuôn mẫu lớp định nghĩa một họ các lớp liên quan dựa trên các đối số kiểu được truyền cho lớp khi khởi tạo. Các khuôn mẫu hàm cũng tương tự như các khuôn mẫu lớp nhưng xác định một họ các hàm. Với khuôn mẫu hàm, ta có thể chỉ định một tập hợp các hàm dựa trên cùng một cách thực thi nhưng hoạt động trên các kiểu hoặc các lớp khác nhau. Khuôn mẫu hàm sau đây thực hiện hoán đổi hai tham số a và b:
template< class T > void MySwap( T& a, T& b ) {
T c(a);
a = b;
b = c;
}
int main() {
}
Mẫu trên xác định một họ các hàm hoán đổi các giá trị của các đối số. Từ mẫu này, ta có thể tạo các hàm sẽ hoán đổi các kiểu int, long và cả các kiểu do người dùng định nghĩa. Hàm MySwap thậm chí sẽ hoán đổi các lớp nếu hàm tạo sao chép và toán tử gán của lớp được định nghĩa hoàn chỉnh. Ngoài ra, khuôn mẫu hàm còn ngăn việc hoán đổi các đối tượng thuộc các kiểu khác nhau, bởi vì trình biên dịch đã xác định được các kiểu tham số a và b tại thời gian biên dịch.
Mặc dù ta có thể viết hàm này không cần template bằng cách sử dụng các con trỏ void, tuy nhiên việc dùng template là an toàn hơn về kiểu. Hãy xem xét các ví dụ sau,
int j = 10;
int k = 18;
CString Hello = "Hello, Windows!";
MySwap( j, k ); //OK
MySwap( j, Hello ); //error
Ở lời gọi MySwap thứ hai gây ra lỗi lúc biên dịch, bởi vì trình biên dịch không thể tạo ra hàm MySwap với các tham số thuộc các kiểu khác nhau. Nếu con trỏ void được sử dụng, cả hai lệnh gọi hàm sẽ biên dịch bình thường, nhưng hàm có thể sẽ không hoạt động chính xác trong lúc chạy.
Các đối số của khuôn mẫu hàm cũng có thể được đặc tả một cách tường minh, như sau,
template<class T> void f(T) {}
int main(int j) {
f<char>(j); // Generate the specialization f(char).
// If not explicitly specified, f(int) would be deduced.
}
Khi đối số mẫu được chỉ định rõ ràng, các chuyển đổi ngầm định bình thường được thực hiện để chuyển đổi các đối số hàm thành kiểu tham số mẫu hàm tương ứng. Trong ví dụ trên, trình biên dịch sẽ chuyển đổi j thành kiểu char.
Khởi tạo khuôn mẫu hàm
Khi một khuôn mẫu hàm được gọi lần đầu tiên cho mỗi kiểu, trình biên dịch sẽ khởi tạo một phiên bản của hàm template cho kiểu tương ứng đó. Việc khởi tạo này sẽ được gọi mỗi khi hàm được dùng với kiểu. Nếu ta có một số lần khởi tạo giống hệt nhau, ngay cả trong các module khác nhau, thì chỉ một bản sao của việc khởi tạo sẽ lưu trong tệp thực thi sau cùng.
Các mẫu hàm có thể được khởi tạo rõ ràng bằng cách khai báo mẫu với một kiểu cụ thể làm đối số. Ví dụ,
// function_template_instantiation.cpp
template<class T> void f(T) { }
// Instantiate f with the explicitly specified template.
// argument 'int'
//
template void f<int> (int);
// Instantiate f with the deduced template argument 'char'.
template void f(char);
int main()
{
}
Để lại một bình luận