0Pricing
C++ Academy · 课时

编写自定义特征

构建您自己的类型特征

编写自定义特征 是 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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 查询类型
  2. 转换类型
  3. 条件逻辑
  4. 编写自定义特征
← 返回 C++ Academy