大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
前言
如果想要知道一个表达式的数据类型但又不想对表达式进行求值, 那么auto
似乎就不满足这中要求, c++11加入了decltype
操作符,它的功能与auto
类似, 都是进行类型推导, 但是decltype
就能对某一表达式的类型进行推导并且不求表达式的值.
因为decltype
在很多的时候并不同于auto
操作符, 所以我会将大部分的不同罗列出来, 比如 : 数组, 顶层const等.
decltype
decltype的声明 :
decltype(exp()) x; // exp()可以是任何的表达式
1. decltype与普通类型
先来看看怎么使用decltype操作符
int i = 0;
decltype(i) di; // 需要传入一个表达式才行, di并不必须要初始化
decltype(i + 0) j;
decltype(function()) f;
auto ai = i; // auto必须对其进行初始化
与auto
不同, decltype
根据表达式就能推导出类型, 所以不需要必须对创建的变量进行初始化, 而auto是需要根据右值的类型进行推导出左值的参数类型, 所以必须在创建的时候进行初始化.
2. decltype与数组
decltype
推导数组类型的时, 推导的并不是指针类型, 而是数组类型.
int a[10]{
0};
decltype(a) da; // 这里推导的da是一个 int[10] 类型的数组, 不是指针
decltype(a + 1) pa; // 这里推导的da是指针
auto pa = a; // auto推导的pa是一个指针
pa = &a[0]; // success, 因为pa是指针
da = &a[0]; // error. da类型是 int[10], 不是指针
用decltype
推导类型就一定要注意, 以上的例子可能以后些代码就会遇到的问题. 同时可以看出来auto
比decltype
多做了一层转换, 将数组转换成了指针.
3. decltype与顶层const
在分析顶层const时分析过, auto
会忽略掉顶层const, 即
const int cc = 0;
auto a = cc; // auto忽略了顶层const, 所以a的其实只是int类型
而**decltype
在推导时并不会忽略顶层const**
const int cc = 0;
decltype(cc) dc = 1; // 必须对dc进行初始化, 因为dc是const int类型
这里也就可以看出来decltype
很”老实”, 给我什么类型就返回什么类型, 而auto
很”聪明”, 知道做一些转换.
4. decltype与引用
引用也是一样, auto
会将引用忽略掉, 而decltype
则会保留引用. 即
int j = 0; int &reference_j = j;
decltype(reference_j) dj = j; // 必须进行初始化, 因为dj是引用类型, 并不是int类型
auto aj = reference_j; aj = 1; // success, auto会忽略掉引用, aj只是一个int类型
关于引用decltype
还没有完, 因为不注意可能在使用decltype
就会出问题.
int i = 0;
decltype((i)) j; // error
我们在decltype中加上了一个()
, 导致的结果就不一样了, 这里的 j 必须进行绑定, 因为他是引用.
记住 : decltype((variable)), 有双括号时结果永远都是引用.
5. decltype与表达式求值结果
本来是想将这个放在引用中来讲, 但是还是抽离出来, 不然可能会混淆的.
如果decltype
中传入的不是一个表达式, 而是一个表达式求值的结果是一个左值, 则推导出来的类型是引用. 就如 : decltype(i = 0)
返回的是引用. (需要解释一下 : 在c中 i=0这样的表达式返回的结果是一个右值, 而在c++中i=0返回的是一个左值. 可以通过(i=j)++进行验证, c中会报错, c++会正常运行.)
int i;
decltype(i = 0) j = i; // j必须绑定, 因为decltype推导出来的是引用
同样, 指针解引用返回的也是左值, 所以
int a[] = {
1, 2};
decltype(*a) b = i; // decltype推导出来的是引用, 因为*a表达式的结果是一个左值
decltype(&a[0]) ptr; // decltype推导出的类型是 int **
6. decltype与模板
在模板中, 编译器能自行推导出传入函数的参数类型, 但是无法推导出返回值的类型, 这时我们就可以用decltype
来解决这个问题.
template<typename T1, typename T2>
T2 func(T1 t1) {
return t1 + t1;} // error. T2的类型无法推导出来
template<typename T1, typename T2>
auto func(T1 t1) -> decltype(t1+t2) // success, 返回值的类型可以通过decltype推导出来
{
return t1 + t1;}
这里auto
放在函数前面只是一个返回类型的占位符, 并不是auto
来推导返回值类型, 而是decltype
在函数返回的时候来推导返回值的类型
在c14中decltype
也有所修改, 在返回值后置中做了一些修改, 可以不用后置, 使用可以如下 :
template<typename T1, typename T2>
decltype(auto) func(T1 t1) // success, 返回值的类型可以通过decltype推导出来
{
return t1 + t1;}
总结
本节罗列出了decltype
的使用方法以及使用时的注意点, 这里做一个总体的归纳
decltype
通过表达式推导出来的是表达式的类型 (即decltype(variable) )- 表达式求值的结果是左值, 则推导出来的是表达式的类型的引用 (即 decltype(variable = 0))
- 表达式是引用, 则推导出来的是引用 (即 decltype(reference) )
- 表达式加了括号的, 则推导出来的是表达式的类型的引用 (即 decltype((variable)) )
- 表达式是数组的首地址, 则推导出来的是数组类型 (即 decltype(arrary) )
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/195741.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...