Đây chỉ là cách giải quyết tình trạng quá tải hoạt động. Khi tra cứu hoàn thành nó tìm thấy cả mẫu và chức năng. Các kiểu mẫu sau đó được suy ra và độ phân giải quá tải bắt đầu. Trong trường hợp của một đối số kiểu MyClass
hai candiates là:
void func<MyClass>(MyClass const&);
void func(MyClass const&);
nào là bình đẳng trận đấu tốt cho các đối số, nhưng thứ hai là một tổ chức phi mẫu được ưa thích. Trong trường hợp của MyClassDer
:
void func<MyClassDer>(MyClassDer const&);
void func(MyClass const&);
Trong trường hợp này là người đầu tiên là một ứng cử viên tốt hơn so với một thứ hai, như một thứ hai đòi hỏi một sự chuyển đổi có nguồn gốc-to-base và được nhặt.
Có các cách tiếp cận khác nhau để gửi trực tiếp đến mã của bạn. Cách đơn giản nhất chỉ là ép buộc kiểu của đối số là MyClass
và vì thế dự phòng cho trường hợp ban đầu:
func(static_cast<MyClass&>(myClassDer));
Trong khi đơn giản, điều này cần phải được thực hiện ở khắp mọi nơi và nếu bạn quên chỉ trong một nơi, điều sai sẽ được gọi là. Phần còn lại của giải pháp là phức tạp và bạn có thể muốn xem xét liệu sẽ không tốt hơn nếu chỉ cung cấp các tên hàm khác nhau.
Một trong những tùy chọn được sử dụng SFINAE để vô hiệu hóa các mẫu khi các loại có nguồn gốc từ MyClass
:
template <typename T>
typename std::enable_if<!std::is_base_of<MyClass,MyClassDer>::value>::type
func(T const & t) { ... }
Trong trường hợp này, sau khi tra cứu, trình biên dịch sẽ thực hiện loại trừ, và nó sẽ suy T
để là MyClassDer
, sau đó nó sẽ đánh giá kiểu trả về của hàm (SFINAE cũng có thể được áp dụng cho một đối số mẫu hoặc hàm khác). is_base_of
sẽ mang lại false
và enable_if
sẽ không có loại lồng nhau. Khai báo hàm sẽ không đúng định dạng và trình biên dịch sẽ thả nó, để lại độ phân giải được thiết lập với một ứng cử viên duy nhất, quá tải không mẫu.
Tùy chọn khác sẽ cung cấp giao diện mẫu đơn và gửi nội bộ đến mẫu hoặc quá tải (theo tên khác) bằng cách sử dụng công cụ gắn thẻ. Ý tưởng là tương tự, bạn đánh giá đặc điểm bên trong khuôn mẫu và gọi hàm với một kiểu được tạo ra từ đánh giá đó.
template <typename T>
void func_impl(T const&, std::false_type) {...}
void func_impl(MyClass const&, std::true_type) {...}
template <typename T>
void func(T const &x) {
func_impl(x,std::is_base_of<MyClass,MyClassDer>::type());
}
Có các lựa chọn thay thế khác, nhưng đó là hai lựa chọn thay thế phổ biến và phần còn lại chủ yếu dựa trên cùng nguyên tắc.
Một lần nữa, hãy cân nhắc xem vấn đề có đáng giá tính phức tạp của giải pháp hay không. Trừ khi các cuộc gọi đến func
được thực hiện bên trong mã chung, một sự thay đổi đơn giản của tên hàm sẽ giải quyết vấn đề mà không cần thêm sự phức tạp mà bạn hoặc các nhà duy trì khác có thể gặp vấn đề.
Điều này có vẻ là giải pháp đúng. Tôi sẽ xem cách thực hiện điều đó bằng cách tăng cường. – user2811040
@ user2811040 'boost :: enable_if' và' boost :: is_base_of'. Đó là nó. – Angew
@ user2811040 Và nếu không có C++ 11, hãy di chuyển tham số mẫu thứ hai sang thủ thuật con trỏ. – Angew