编写自定义特征
构建您自己的类型特征
编写自定义特征 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。
构建您自己的类型特征
当标准库无法回答您需要的问题时,您可以编写自定义类型特征。类型特征本质上就是一个公开 ::value 或 ::type 的模板。
主模板 + 特化
标准模式是:让主模板默认为 false,再添加一个匹配目标类型的特化,并将其设置为 true。
#include <iostream>
#include <type_traits>
template <typename T>
struct is_ptr : std::false_type {};
template <typename T>
struct is_ptr<T*> : std::true_type {};
int main() {
std::cout << is_ptr<int>::value << "\n";
std::cout << is_ptr<int*>::value << "\n";
return 0;
}继承 integral_constant
通过继承 std::true_type 或 std::false_type,您的类型特征会自动获得 value 成员,并表现得像标准类型特征一样。
容器检测器
通过检查嵌套成员,检测某个类型是否具有容器的特征。这里通过辅助工具,针对是否存在 value_type 类型别名进行特化。
#include <iostream>
#include <vector>
#include <type_traits>
template <typename T, typename = void>
struct has_value_type : std::false_type {};
template <typename T>
struct has_value_type<T, std::void_t<typename T::value_type>> : std::true_type {};
int main() {
std::cout << has_value_type<std::vector<int>>::value << "\n";
std::cout << has_value_type<int>::value << "\n";
return 0;
}解释 std::void_t
std::void_t<...> 会将任何有效的类型列表映射为 void。如果其中任何类型的形式不正确,该特化就会通过 SFINAE 被丢弃,因此最终会使用主模板中的 false_type。
检测成员函数
您可以通过在 void_t 中测试表达式,检测某个类型是否具有可调用的 size()。
#include <iostream>
#include <string>
#include <type_traits>
template <typename T, typename = void>
struct has_size : std::false_type {};
template <typename T>
struct has_size<T, std::void_t<decltype(std::declval<T>().size())>> : std::true_type {};
int main() {
std::cout << has_size<std::string>::value << "\n";
std::cout << has_size<int>::value << "\n";
return 0;
}declval
std::declval<T>() 会在不求值上下文中生成一个类型为 T 的虚拟值,让您无需构造对象即可编写 decltype 表达式。
变换类型特征
自定义类型特征也可以生成类型。这个类型特征会移除一层指针。
#include <iostream>
#include <type_traits>
template <typename T>
struct remove_one_pointer { using type = T; };
template <typename T>
struct remove_one_pointer<T*> { using type = T; };
int main() {
using R = remove_one_pointer<int*>::type;
std::cout << std::is_same_v<R, int> << "\n";
return 0;
}提供 _v 和 _t 辅助工具
通过添加变量模板和别名模板,遵循标准库的风格。
#include <iostream>
#include <type_traits>
template <typename T>
struct is_char : std::false_type {};
template <>
struct is_char<char> : std::true_type {};
template <typename T>
inline constexpr bool is_char_v = is_char<T>::value;
int main() {
std::cout << is_char_v<char> << "\n";
std::cout << is_char_v<int> << "\n";
return 0;
}检测惯用法
void_t 技术可以推广为检测惯用法,实验性的 std::is_detected 对其进行了形式化。C++20 概念让其中许多操作变得更加简洁。
测试您的类型特征
使用 static_assert 验证自定义类型特征,这样任何回归问题都会立即导致构建失败。
#include <type_traits>
template <typename T>
struct is_void_like : std::false_type {};
template <>
struct is_void_like<void> : std::true_type {};
static_assert(is_void_like<void>::value);
static_assert(!is_void_like<int>::value);
int main() { return 0; }快速检查
回顾 std::void_t 的作用。
总结
您学习了如何编写自定义类型特征。
- 主模板默认为 false;特化将其设置为 true
- 继承
true_type/false_type void_t与declval共同实现检测惯用法- 添加
_v/_t辅助工具,并使用static_assert进行测试
常见问题解答
「编写自定义特征」课时是免费的吗?
是的 — 「编写自定义特征」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。
「编写自定义特征」这节课中我会学到什么?
构建您自己的类型特征 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C++ Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「编写自定义特征」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C++ Academy 课中编写并运行代码吗?
能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。