enable_if 模式
以经典方式约束模板
enable_if 模式 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。
什么是 enable_if
std::enable_if 是一个小型特征,可以有条件地定义 type 成员。条件为真时该类型存在;条件为假时,外围模板会通过 SFINAE 被移除。
- 位于
<type_traits>中。 - 它是约束模板的经典工具。
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
doubleIt(T v) { return v * 2; }
int main() {
std::cout << doubleIt(21) << '\n';
return 0;
}工作原理
只有当 Cond 为真时,enable_if<Cond, T>::type 才是 T。如果条件为假,就不存在 type 成员,因此替换会失败。
#include <iostream>
#include <type_traits>
int main() {
std::cout << std::boolalpha;
std::cout << std::is_same<std::enable_if<true, int>::type, int>::value << '\n';
return 0;
}返回类型中的 enable_if
最常见的放置位置是返回类型。只有条件成立时,函数才会存在。
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
half(T v) { return v / 2; }
int main() {
std::cout << half(5.0) << '\n';
return 0;
}作为模板参数的 enable_if
另一种惯用写法是将 enable_if 放入带默认值的模板参数中,从而保持返回类型简洁。
#include <iostream>
#include <type_traits>
template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
T triple(T v) { return v * 3; }
int main() {
std::cout << triple(4) << '\n';
return 0;
}enable_if_t 快捷写法
C++14 增加了别名 std::enable_if_t<Cond, T>,这样您可以省略 typename ...::type 这一冗长写法。
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_integral<T>::value, T>
negate(T v) { return -v; }
int main() {
std::cout << negate(8) << '\n';
return 0;
}配对两个重载
提供互补的条件,使得对于任何类型恰好只有一个重载有效,并且不会产生歧义。
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_integral<T>::value, const char*>
category() { return "integer"; }
template <typename T>
std::enable_if_t<!std::is_integral<T>::value, const char*>
category() { return "non-integer"; }
int main() {
std::cout << category<int>() << ' ' << category<double>() << '\n';
return 0;
}组合条件
对特征值使用逻辑运算符来表达更丰富的约束,例如“整数类型且带符号”。
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value, T>
magnitude(T v) { return v < 0 ? -v : v; }
int main() {
std::cout << magnitude(-12) << '\n';
return 0;
}约束构造函数
您可以将 enable_if 放在构造函数的模板参数上,使其仅对兼容类型可用。
#include <iostream>
#include <type_traits>
struct Wrapper {
int value;
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
Wrapper(T v) : value(static_cast<int>(v)) {}
};
int main() {
Wrapper w(42);
std::cout << w.value << '\n';
return 0;
}默认模板参数陷阱
如果两个重载的区别仅在于带默认值的 enable_if 模板参数,它们会被视为重复定义。请使用不同的形式,例如将其中一个条件放在返回类型上。
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_integral<T>::value, void>
printKind() { std::cout << "int\n"; }
template <typename T>
std::enable_if_t<std::is_floating_point<T>::value, void>
printKind() { std::cout << "float\n"; }
int main() {
printKind<int>();
printKind<double>();
return 0;
}与概念比较
C++20 的概念用清晰得多的语法取代了大多数 enable_if 用法,但对于 C++20 之前的代码和某些边界情况,enable_if 仍然不可或缺。
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_arithmetic<T>::value, T>
square(T v) { return v * v; }
int main() {
std::cout << square(6) << ' ' << square(1.5) << '\n';
return 0;
}完整示例
将所有内容结合起来:在编译期选择一个函数族,以不同方式格式化整数和浮点数。
#include <iostream>
#include <type_traits>
template <typename T>
std::enable_if_t<std::is_integral<T>::value, void>
format(T v) { std::cout << "int[" << v << "]\n"; }
template <typename T>
std::enable_if_t<std::is_floating_point<T>::value, void>
format(T v) { std::cout << "float(" << v << ")\n"; }
int main() {
format(10);
format(3.5);
return 0;
}快速检查
测试您对 enable_if 的理解。
回顾
您学习了经典的 enable_if 模式:
- 仅当条件为真时定义
::type,从而启用 SFINAE - 放在返回类型或带默认值的模板参数中
- 使用
enable_if_t别名,并通过逻辑运算符组合特征 - C++20 中的概念取代了它,但它仍被广泛使用
至此,模板特化与 SFINAE 课程全部完成。
用 AI 导师学习 C++ — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 51
- 课程
- 203
常见问题解答
「enable_if 模式」课时是免费的吗?
是的 — 「enable_if 模式」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。
「enable_if 模式」这节课中我会学到什么?
以经典方式约束模板 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C++ Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「enable_if 模式」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C++ Academy 课中编写并运行代码吗?
能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。