C++填坑系列——类型推导 decltype
decltype
decltype
主要是为了解决类型推导的问题,特别是在模板编程和泛型编程中应用较广泛。
decltype
关键字用于以表达式为参数,推导表达式返回的类型,该类型会保留所有信息。
c++11提出的新特性,decltype
关键字。
和auto
一样都是用来做编译时类型推导的,但是也有一些区别:
auto
: 从变量声明的表达式中推导变量类型,如:auto a = b + c;
decltype
: 以表达式为参数,推导表达式返回的类型,如:decltype(a+b) c;
用法:
1. decltype+变量
会推导出该变量类型的所有信息(包括const
和reference
),数组和函数也不会退化;
int main() { int arr[2] = {0, 1}; int* p = arr; int a = 10; int& b = a; const int c = 20; const int& d = a; decltype(a) e1; // int decltype(b) e2 = a; // int& 保留引用的信息 decltype(c) e3 = 10; // const int 保留const的信息 decltype(d) e4 = a; // const int& 保留const和引用的信息 decltype(arr) e5; // int[2] 推导出类型还是数组 decltype(p) e6; // int * 推导出类型还是指针 }
2. decltype+表达式
会返回表达式结果对应的类型;表达式的结果分为左值/右值,左值->得到该类型的左值引用;右值->得到该类型;
注意下面代码Sample
的第2和第3个结果,推导出的类型不一样,这是因为:
decltype
单独作用于对象,没有使用该对象的表达式属性,而是该变量;要想使用表达式,可以加括号。
decltype(s)
这里推导对象s
的类型就是Sample
,decltype((s))
这里推导表达式结果的类型,左值得到左值引用类型。
class Sample {}; int func1() { return 10; } Sample& func2(Sample& s) { return s; } int main() { int a = 10; int& b = a; decltype(a + b) e11; // int, 表达式a+b的结果是个右值 decltype(func1()) e12; // int, 函数func()返回的结果是个右值 Sample s; decltype(std::move(s)) e13 = std::move(s); // 1. Sample&& decltype(s) e14; // 2. Sample decltype((s)) e15 = e14; // 3. Sample& decltype(func2(s)) e16 = e14; // 4. Sample& return 0; }
3. 如何执行?
decltype
并不会实际计算表达式的值,编译器只会分析表达式结果并得到类型;这个注意和auto
的区分。
4. 使用场景:
- 不需要计算;
有些场景需要从表达式只是推导出类型,而不需要确切的计算,以及不需要使用表达式的值初始化另一个变量;
auto a = b + c;
虽然可以推导类型,但是会使用表达式初始化另一个变量;
decltype(b + c) a;
这里只会用a+b
的结果推导类型,并不会真的执行运算。
- 与
(trailing return type)
和auto
配合;
c++11引入的尾置返回类型(trailing return type)
和decltype
可以有更好的配合。
c++11之前,函数模板的返回类型不能依赖于模板参数推导。
c++11之后,尾置返回类型允许使用auto
关键字,然后在函数参数声明之后推导返回类型。
下面的代码一,使用auto
自动推导函数返回类型编译器会报错:auto函数需要尾随的返回类型(c++11会报错,但在c++14解决了该问题)",所以在代码二中,可以结合decltype
来进行自动推导,decltype(lhs + rhs)
用于推导两个参数相加的结果类型。
// 代码一: // c++11中会报错:“auto”函数需要尾随的返回类型 // c++14中不会报错,可以直接使用auto来推导 template <typename T, typename U> auto add(const T& lhs, const U& rhs) { return lhs + rhs; }
// 代码二:c++11中添加-> decltype(lhs + rhs)可编译通过了就 template <typename T, typename U> auto add(const T& lhs, const U& rhs) -> decltype(lhs + rhs) { return lhs + rhs; }
(trailing return type)
在模板编程和泛型编程中,解决传统函数返回类型声明中的一些限制,使得函数的返回类型可以很好地依赖于其参数类型;
通过decltype
尾置,来自动推导依赖参数的类型
- 处理复杂的返回类型时;
在模板编程中,有时候需要处理非常复杂的类型,或者类型依赖于模板参数。而decltype
可以帮我们很准确地推导出类型。
下面的代码中,利用decltype
推导Container
的迭代器类型,当然这个位置和auto
的使用功能差不多了就。
template <typename Container> void foo(const Container& c) { decltype(c.begin()) it1 = c.begin(); auto it2 = c.begin(); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通