SFINAE (Substitution Failure Is Not An Error)
SFINAE là một nguyên tắc trong siêu lập trình khuôn mẫu C++ cho phép trình biên dịch chọn hàm hoặc lớp thích hợp khi chuyên biệt hóa khuôn mẫu cụ thể không thành công trong quá trình thay thế. Thuật ngữ "substitution failure" đề cập đến quá trình mà trình biên dịch cố gắng thay thế các đối số khuôn mẫu thành khuôn mẫu hàm hoặc khuôn mẫu lớp. Nếu sự thay thế gây ra lỗi, trình biên dịch sẽ không coi chuyên biệt hóa cụ thể đó là một ứng viên và sẽ tiếp tục tìm kiếm một chuyên biệt hóa hợp lệ.
Ý tưởng chính đằng sau SFINAE là nếu xảy ra lỗi thay thế, nó sẽ bị bỏ qua một cách âm thầm và trình biên dịch tiếp tục khám phá các chuyên biệt hóa hoặc quá tải mẫu khác. Điều này cho phép bạn viết mã linh hoạt và chung hơn, vì nó cho phép bạn có nhiều chuyên biệt hóa cho các tình huống khác nhau.
Ví dụ mã code
Đây là một ví dụ minh họa hoạt động của SFINAE:
#include <iostream>
#include <type_traits>
template <typename T, typename = void>
struct foo_impl {
void operator()(T t) {
std::cout << "Called when T is not arithmetic" << std::endl;
}
};
template <typename T>
struct foo_impl<T, std::enable_if_t<std::is_arithmetic<T>::value>> {
void operator()(T t) {
std::cout << "Called when T is arithmetic" << std::endl;
}
};
template <typename T>
void foo(T t) {
foo_impl<T>()(t);
}
int main() {
int a = 5;
foo(a); // đầu ra: Được gọi khi T là số học
std::string s = "example";
foo(s); // đầu ra: Được gọi khi T không phải là số học
}
Trong ví dụ này, chúng tôi xác định hai chuyên biệt hóa khuôn mẫu hàm foo. Cái đầu tiên được chạy khi T là kiểu số học, trong khi cái thứ hai được chạy khi T không phải là kiểu số học. std::enable_if_t bên trong danh sách tham số mẫu cho phép ta kiểm soát chuyên biệt hóa nào hợp lệ đối với một kiểu T nhất định.
Khi gọi foo(a) bằng một số nguyên, chuyên biệt hóa đầu tiên được chọn và khi gọi foo(s) bằng một chuỗi, chuyên biệthóa thứ hai sẽ được chọn. Nếu không có chuyên biệt hóa hợp lệ, mã code sẽ không biên dịch được.