C++ decltype 类型推导
2022/9/8 14:24:02
本文主要是介绍C++ decltype 类型推导,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录- decltype 说明符(C++11)
- 使用 decltype 保留auto 的引用属性(C++14)
- decltype 的推导规则
- cv 限定符(const / volatile)的推导
- decltype(auto) (C++14)
- 参考资料
decltype 说明符(C++11)
C++11 引入了 decltype 说明符,decltype 可以获取一个对象或者表达式的类型。
使用起来也很简单:
#include <iostream> int main() { int x1 = 0; decltype(x1) x2 = 0; // x2 被推导为 int 类型(变量 x1 的类型) std::cout << typeid(x2).name() << std::endl; double x3 = 0; decltype(x1 + x3) x4 = x1 + x3; // x4 被推导为 double 类型(表达式 x1 + x3 的类型) std::cout << typeid(x4).name() << std::endl; return 0; }
运行结果:
linrongjian@hhb-ssd:/data/modern_cpp$ g++ -std=c++11 decltype_example.cpp -o decltype_example linrongjian@hhb-ssd:/data/modern_cpp$ ./decltype_example i d
相比 auto
,decltype
除了可以推导表达式的类型,还可以用来推导类中的非静态成员变量的类型(auto
是不可以的),
使用 decltype 保留auto 的引用属性(C++14)
之前讲 auto
关键字的时候说过 auto
的推导规则其中之一是:使用 auto 声明变量初始化时,目标对象如果是引用,则引用属性会被忽略。
比如下面的代码:
#include <iostream> #include <cassert> #include <type_traits> template <class T> auto return_ref(T& t) { return t; } int main() { int x1 = 0; static_assert(std::is_reference_v<decltype(return_ref(x1))>); }
我们引用传递参数 t
,希望 return_ref
可以返回一个引用,然而事实上这里 auto
被推导为值类型:
一个解决办法是给 auto
加上 &
,另一个解决办法就是使用 decltype
作为尾置返回类型:
#include <iostream> #include <cassert> #include <type_traits> template <class T> auto return_ref(T& t) -> decltype(t) { return t; } int main() { int x1 = 0; static_assert(std::is_reference_v<decltype(return_ref(x1))>); }
decltype 的推导规则
对于一个类型为 T
的变量或者表达式 e
,decltype(e)
的推导规则有 5
条:
-
如果
e
是一个未加括号的表达式(结构化绑定除外)或者未加括号的类成员访问,则decltype(e)
推断出e
的类型是T
。如果不存在这样的类型(比如表达式里的变量不在当前作用域内)或者
e
是重载函数(运行时多态,decltype
要求是编译期确定返回类型),则无法进行推导。 -
如果
e
是一个函数调用或者仿函数调用,那么decltype(e)
推断出的类型是其返回值的类型。 -
如果
e
是一个类型为T
的左值,则decltype(e)
是T&
。这就是上面的那个例子返回的是一个引用的原因。
-
如果
e
是一个类型为T
的将亡值,则decltype(e)
是T&&
。 -
其他情况,
decltype(e)
是T
。
cv 限定符(const / volatile)的推导
decltype(e)
推导的类型会同步 e
的 cv
限定符。
比如:
const int i = 0; decltype(i); // declytpe(i) 推导类型为 const(注意这里和 auto 的不同)
如果 e
是类的成员变量时,要同步 cv
限定符需要加上括号。
struct A { double x; }; const A* a = new A(); decltype(a->x); // decltype(a->x) 推导类型为 double,const 属性被忽略
上面的代码没有给 a->x
加上括号,推导的类型没有 const
属性,带上括号之后推导类型为 const double
:
struct A { double x; }; const A* a = new A(); decltype((a->x)); // decltype((a->x)) 推导类型为 const double
总结:当 e 是加上了括号的数据成员时,父对象表达式的 cv 限定符会同步到推导结果。
decltype(auto) (C++14)
C++14 运行时用 decltype(auto) 告诉编译器使用 decltype 的规则来推导 auto.
decltype(auto)
必须单独使用,也就是不能再给它加上指针、引用还有 cv
属性。
再看之前的 return_ref
的例子,如果我们还是想用 auto
来给 return_ref
函数返回一个引用,而我们却不想使用 auto&
(在泛型编程的情况下只能表现引用语义的表达能力是不够的),就可以使用 decltype(auto)
:
#include <iostream> #include <cassert> #include <type_traits> template <class T> decltype(auto) return_ref(T& t) { return t; } int main() { int x1 = 0; static_assert(std::is_reference_v<decltype(return_ref(x1))>); }
这里由于使用了 decltype(auto)
,因此 auto
按照 decltype
的规则来推导类型,这里 e
是个左值引用,按照推导规则 3
,返回一个引用,所以我们的断言可以通过。
参考资料
- 现代C++语言核心特性解析
- cppreference: decltype specifier
这篇关于C++ decltype 类型推导的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-26怎么使用nsenter命令进入容器?-icode9专业技术文章分享
- 2024-12-26导入文件提示存在乱码,请确定使用的是UTF-8编码怎么解决?-icode9专业技术文章分享
- 2024-12-26csv文件怎么设置编码?-icode9专业技术文章分享
- 2024-12-25TypeScript基础知识详解
- 2024-12-25安卓NDK 是什么?-icode9专业技术文章分享
- 2024-12-25caddy 可以定义日志到 文件吗?-icode9专业技术文章分享
- 2024-12-25wordfence如何设置密码规则?-icode9专业技术文章分享
- 2024-12-25有哪些方法可以实现 DLL 文件路径的管理?-icode9专业技术文章分享
- 2024-12-25错误信息 "At least one element in the source array could not be cast down to the destination array-icode9专业技术文章分享
- 2024-12-25'flutter' 不是内部或外部命令,也不是可运行的程序 或批处理文件。错误信息提示什么意思?-icode9专业技术文章分享