文章

类型萃取

类型萃取

[TOC]

类型萃取1

类型萃取(Type Traits)是 C++11 引入的一组模板,用于在编译时获取类型的属性,就是把类型提取出来。

以一部分函数和关键词为例:

(1) std::is_same_v<T1, T2>

判断 T1 和 T2 是否是同一种类型。

(2) std::is_integral<T>::value

判断 T 是否为整型。

C++14提供一个更好的写法:std::is_integral_v<T>,与其等效。

(3) std::decay<T>::type

C++14中引入了一个更好的写法:std::decay_t<T>,与其等效。

std::decay是一个类型特征,它模仿了函数参数传递时的类型转换规则。

具体来说,std::decay执行以下操作:[^5]

  1. 如果T是一个数组类型,它会被转换为指向其首元素的指针。

  2. 如果T是一个函数类型,它会被转换为指向该函数的指针。

  3. 如果T是一个引用类型,引用部分会被移除。

  4. 如果T带有const、volatile或是const volatile限定符,这些限定符会被移除。

简而言之,std::decay “去除”了一个类型的一些属性,例如引用性质和cv限定符(const和volatile),使其成为一个更通用的、”平凡”类型,这通常是用于模板编程中类型推导的场景。

(4) decltype(T)

decltype是一个关键字,它的字面含义是 “declared type”,即 “声明的类型”。它用于查询表达式的类型而不实际计算表达式的值。2

这个关键字在C++11标准中引入,用于在编译时推断表达式的类型,特别是在模板编程和类型推导的上下文中非常有用。

decltype提取了 T 的类型,而不进行任何求值。这意味着decltype(T)的结果是 T 的类型,包括其const/volatile 限定符以及引用性质。

decltype 的常见用法是在创建泛型代码时,你需要根据某个参数或表达式的类型来定义变量,但又不想或不能改变这个表达式的值。例如:

1
2
int x = 5;
decltype(x) y = 10; // y的类型为int,因为x的类型是int

更复杂的表达式示例:

1
2
3
4
5
6
7
8
int a = 3;
int& b = a;
decltype(b) c = a; // c的类型是int&,因为b的类型是int&

auto f = [](int a, int b) -> int {
    return a * b;
};
decltype(f) g = f; // g的类型是与lambda函数f相同的类型

decltype 的另一个重要用途是在模板元编程和泛型编程中推导返回类型,尤其是在与 auto 结合使用的 trailing return type 语法中:

1
2
3
4
template <typename X, typename Y>
auto add(X x, Y y) -> decltype(x + y) {
    return x + y; // 使用decltype自动推断返回类型
}

在这个函数模板中,decltype(x + y) 能够根据传递给函数的参数类型推断 add 函数的返回类型。这在C++11 中对于复杂的类型推导非常有帮助,尤其是当函数的返回类型依赖于模板参数的表达式时。

随着 C++14 和C++17 标准的发展,推导返回类型变得更加容易,但 decltype 仍然在需要显式类型信息时发挥着重要作用。

参考文章

本文由作者按照 CC BY 4.0 进行授权