SFINAE 是 C++
中的一种语言规则,其大意是:编译器在尝试将模版形参替换为模板实参的时候,如果替换后得到的结果不是合法的代码(替换失败),编译器不会报错,而仅仅是忽略它。
SFINAE
1 2 3 4
| template<typename T> bool equal(const T& a, const T& b) { return a == b; }
|
如果是 int 类型的数据这里不会出错,但是 double
浮点型就有问题,因为浮点数无法判断是否相等。
也许你想到特化模板,对浮点数特别处理,比方说:
1 2 3 4 5
| template<> bool equal<double>(const T& a, const T& b) { cout << "无法处理 double" << endl; return true; }
|
但如果我们用 SFINAE 规则会如何处理?
1 2 3 4 5 6 7 8 9
| #include <type_traits>
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>> > bool equal(const T& a, const T& b) { return a == b; }
|
std::enable_if<条件>::type
用于启用或禁用模板。而代码中的std::enable_if_t<条件>
是 std::enable_if<条件>::type
的简写。
std::is_integral<T>::value
是 C++
类型特征的一部分,如果是 int 类型返回 true,如果不是就返回
false。而代码中的std::is_integral_v<T>
是
std::is_integral<T>::value
的简写。
SFINAE 的替代品:C++20
Concepts
1 2 3 4 5
| template<typename T> requires std::is_integral_v<T> bool equal(const T &a, const T &b) { return a == b; }
|
更简洁的写法:
1 2 3 4
| template<std::integral T> bool equal(const T &a, const T &b) { return a == b; }
|
如果你要限制多个不同的类型,怎么办?通过 || 来连接多个限制。
1 2 3 4 5 6 7
| #include <concepts>
template <typename T> requires (std::integral<T> || std::floating_point<T>) bool equal(const T& a, const T& b) { return a == b; }
|
你还可以这么做:
1 2 3 4 5 6 7
| template <typename T> concept Number = std::integral<T> || std::floating_point<T>;
template <Number T> bool equal(const T& a, const T& b) { return a == b; }
|
参考文章
从
SFINAE 到 C++20 Concepts