Thiếu chuyên biệt hóa template
Trong một số trường hợp, có thể cần cung cấp một triển khai mẫu cho một kiểu cụ thể (hoặc tập hợp các kiểu) theo cách khác với triển khai chung. Ví dụ, thường có ý nghĩa khi chuẩn bị một phiên bản đặc biệt của hàm hoán đổi cho các con trỏ hoặc mảng. Trong những trường hợp như vậy, C++ cho phép thực hiện cái gọi là chuyên biệt hóa mẫu, tức là định nghĩa một phiên bản của mẫu trong đó tham số kiểu chung T được thay thế bằng kiểu cụ thể mong muốn.
Khi chuyên biệt hóa các mẫu hàm và phương thức, các kiểu cụ thể phải được chỉ định cho tất cả các tham số. Đây được gọi là chuyên biệt hóa hoàn toàn.
Trong trường hợp các mẫu kiểu đối tượng của C++, chuyên biệt hóa có thể không chỉ hoàn toàn mà còn một phần: nó chỉ định kiểu của chỉ một số tham số (và phần còn lại sẽ được suy ra hoặc chỉ định khi mẫu được khởi tạo). Có thể có nhiều chuyên biệt hóa một phần: điều kiện duy nhất cho việc này là mỗi chuyên biệt hóa phải mô tả một tổ hợp kiểu duy nhất.
Thật không may, trong MQL5 không có chuyên biệt hóa theo nghĩa đầy đủ của từ này.
Chuyên biệt hóa hàm mẫu không khác gì nạp chồng. Ví dụ, với mẫu sau đây func
:
template<typename T>
void func(T t) { ... }
2
Cho phép cung cấp triển khai tùy chỉnh của nó cho một kiểu đã cho (như string
) theo một trong các dạng:
// chuyên biệt hóa rõ ràng
template<>
void func(string t) { ... }
2
3
Hoặc:
// nạp chồng thông thường
void func(string t) { ... }
2
Chỉ một trong các dạng phải được chọn. Nếu không, chúng ta sẽ nhận được lỗi biên dịch "'func' - hàm đã được định nghĩa và có thân".
Đối với chuyên biệt hóa của các lớp, việc kế thừa từ các mẫu với việc chỉ định các kiểu cụ thể cho một số tham số mẫu có thể được xem như một tương đương của chuyên biệt hóa một phần của chúng. Các phương thức mẫu có thể được ghi đè trong lớp dẫn xuất.
Ví dụ sau (TemplatesExtended.mq5
) cho thấy một số tùy chọn sử dụng các tham số mẫu làm kiểu cha, bao gồm các trường hợp một trong số chúng được chỉ định là cụ thể.
#define RTTI Print(typename(this))
class Base
{
public:
Base() { RTTI; }
};
template<typename T>
class Derived : public T
{
public:
Derived() { RTTI; }
};
template<typename T>
class Base1
{
Derived<T> object;
public:
Base1() { RTTI; }
};
template<typename T> // chuyên biệt hóa "hoàn toàn"
class Derived1 : public Base1<Base> // 1 trong 1 tham số được đặt
{
public:
Derived1() { RTTI; }
};
template<typename T,typename E>
class Base2 : public T
{
public:
Base2() { RTTI; }
};
template<typename T> // chuyên biệt hóa "một phần"
class Derived2 : public Base2<T,string> // 1 trong 2 tham số được đặt
{
public:
Derived2() { RTTI; }
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Chúng ta sẽ cung cấp một khởi tạo của một đối tượng theo mẫu bằng cách sử dụng một biến:
Derived2<Derived1<Base>> derived2;
Ghi nhật ký kiểu gỡ lỗi bằng macro RTTI tạo ra kết quả sau:
Base
Derived<Base>
Base1<Base>
Derived1<Base>
Base2<Derived1<Base>,string>
Derived2<Derived1<Base>>
2
3
4
5
6
Khi phát triển thư viện được cung cấp dưới dạng nhị phân kín, bạn phải đảm bảo rằng các mẫu được khởi tạo rõ ràng cho tất cả các kiểu mà người dùng tương lai của thư viện dự kiến sẽ làm việc. Bạn có thể làm điều này bằng cách gọi rõ ràng các mẫu hàm và tạo các đối tượng với các tham số kiểu trong một hàm phụ trợ, ví dụ, được liên kết với việc khởi tạo một biến toàn cục.