Android C++ 系列:C++ 最佳实践 6 constexpr 与 decltype
1. 背景
上一篇介绍了 const 关键字,主要修饰变量,起到不可改变的常量作用。有一种值不会改变并且在编译过程就能得到计算结果的表达式我们称为常量表达式。
字面值属于常量表达式,用常量表达式初始化的 const 对象也是常量表达式:
一个对象或者表达式是不是常量表达式由它的数据类型和初始值共同决定,但是在一些复杂的系统中,我们难以分辨一个初始值是不是常量表达式。如何让编译器帮助我们判断是否是常量表达式呢?
2. constexpr
C++11 中,引入了关键字 constexpr,允许将变量声明为 constexpr 类型以便由编译器来验证变量的值是否是常量表达式。
声明为 constexpr 的变量一定是一个常量,而且必须用常量表达式初始化:
constexpr 除了修饰变量还可以修饰函数,这种函数必须是编译时就可以计算到结果。
2.1 constexpr 限制
常量表达式的值需要在编译时就得到计算,所以对声明 constexpr 时用到的类型必须有所限制。
把比较简单,值显而易见,容易计算的类型成为“字面值类型”。算术类型,引用类型和指针都属于字面值类型。
指针和引用都能定义成 constexpr,但是它们的初始值必须是 nullptr 或者 0,或者是存储于某个固定地址中的对象。
函数体内定义的变量一般不是存放在固定地址中,因此 constexpr 指针不能指向函数体内定义的指针。
constexpr 声明中如果定义了指针,限定符 constexpr 仅对指针有效,与指针所指的对象无关。
3. decltype 类型指示符
当我们希望从表达式的类型推断出要定义的变量的类型,但是不想用这个表达式的值初始化变量,这个时候就要用到了 C++11 引入的类型说明符 decltype,它的作用是选择并返回操作数的数据类型:
编译器分析 fun 表达式并得到它的类型,但是不进行实际调用。
3.1 引用在 decltype 的特殊之处
如果 decltype 使用的表达式不是一个变量,则 decltype 返回表达式结果对应的类型。有时有些表达式向 decltype 返回一个引用类型。这时意味着表达式的结果对象能作为一条赋值语句的左值。
如果表达式的内容是解引用操作,decltype 将得到引用类型。
引用和指针本身是 C++比 Java 多的引用和指针已经加大了编程语言的复杂度,现在为它们增加了新特性更是让人眼花缭乱,但是如果不弄明白一是遇到实际问题不知道用什么办法解决;二是看别人代码的时候容易一头雾水。
4. 类型别名
C/C++还有为类型定义别名的能力。比如我们用到的 uint_8 之类跨平台类型都是基于 typedef 方式命名的。
传统的别名定义是使用 typedef:typedef char uint_8
C++11 中引入了一种新的方法,使用 using 方式:using Str = std::string
使用 typedef 给复合类型起名容易踩坑,比如:
const 是对给定类型的修饰,str 是指向 char 的指针,因此 const str 就是指向 char 的常量指针,而不是指向常量字符的指针。
我们往往直接做替换:
理解成指向常量字符的指针。
5. 总结
本文作为 const 内容的延续,介绍了 constexpr 和 decltype 两种修饰符,以及类型别名的两种方式,以及 typedef 别名使用容易遇到的问题。
版权声明: 本文为 InfoQ 作者【轻口味】的原创文章。
原文链接:【http://xie.infoq.cn/article/f208241d0dca3c167fd403db2】。文章转载请联系作者。
评论