C++填坑系列——类型推导 decltype

decltype

decltype主要是为了解决类型推导的问题,特别是在模板编程和泛型编程中应用较广泛。
decltype关键字用于以表达式为参数,推导表达式返回的类型,该类型会保留所有信息。

c++11提出的新特性,decltype关键字。

auto一样都是用来做编译时类型推导的,但是也有一些区别:

  • auto: 从变量声明的表达式中推导变量类型,如:auto a = b + c;
  • decltype: 以表达式为参数,推导表达式返回的类型,如:decltype(a+b) c;

用法:

1. decltype+变量

会推导出该变量类型的所有信息(包括constreference),数组和函数也不会退化;

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的类型就是Sampledecltype((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. 使用场景:

  1. 不需要计算;

有些场景需要从表达式只是推导出类型,而不需要确切的计算,以及不需要使用表达式的值初始化另一个变量;

auto a = b + c;虽然可以推导类型,但是会使用表达式初始化另一个变量;

decltype(b + c) a;这里只会用a+b的结果推导类型,并不会真的执行运算。

  1. (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尾置,来自动推导依赖参数的类型

  1. 处理复杂的返回类型时;

在模板编程中,有时候需要处理非常复杂的类型,或者类型依赖于模板参数。而decltype可以帮我们很准确地推导出类型。

下面的代码中,利用decltype推导Container的迭代器类型,当然这个位置和auto的使用功能差不多了就。

template <typename Container>
void foo(const Container& c) {
decltype(c.begin()) it1 = c.begin();
auto it2 = c.begin();
}
posted @   战斗天使zzy  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示