Fork me on GitHub

C++11新特性:constexpr变量和constexpr函数

C++11新特性:constexpr变量和constexpr函数

​ 本章将介绍constexpr变量和constexpr函数两个知识点。在了解constexpr函数之前,首先要对常量表达式constexpr变量字面值类型字面值常量的定义有一个清晰的了解。

先验知识

1.常量表达式

​ 指值不会改变并且在编译过程中就能够得到计算结果的值

const int max_files = 20;            //max_files是常量表达式
const int limit = max_files + 1;     //limit是常量表达式
int staff_size = 27;                 //staff_size不是常量表达式,因为它的数据类型不是const 
const int sz = get_size();           
//sz不是常量表达式,因为get_size()只有到运行的时候才知道结果,除非它是constexpr修饰的(C++ 11标准)

2.constexpr变量

​ C++11新标准规定,允许将变量声明为constexpr类型以便由编译器验证变量的值是否是一个常量表达式。如果不是,编译器报错。同时,声明为constexpr的变量一定是常量,而且必须用常量表达式初始化。

constexpr int mf = 20;              //正确,20是常量表达式
constexpr int limit = mf + 1;       //正确,mf + 1是常量表达式
constexpr int sz = size();         //未知,若size()函数是一个constexpr函数时即正确,反之错误。

int i = 10;
constexpr int t = i;                //错误,i不是常量

3.字面值类型

声明constexpr变量时用到的类型被称为字面值类型。算术类型、引用、指针、枚举和一些特殊的类都属于字面值类型,而IO库、string类型则不属于字面值类型,也就不能被定义为constexpr。

4.字面值常量

常量是指用const声明或定义一个变量,使之成为常量。如const int bufSize = 512; #bufSize在程序中将不允许被修改,是常量。而字面值常量是指只能用它的值来称呼的,不能被修改的值,如4、3.1415926、0x24、"BEIJING"

5.指针与constexpr

​ 对于指针而言,constexpr仅对指针本身有效与指针所指对象无关

const int *p = nullptr;            //正确,p是一个指向整型常量的指针
constexpr int *q = nullptr;        //正确,但q是一个指向  整数  的  常量指针

​ constexpr指针既可以指向常量也可以指向一个非常量

constexpr int *np = nullptr;         //正确,np是一个指向整数的常量指针,其值为空

int j = 0;
constexpr int i = 42;
//i和j都必须定义在函数体之外,否则constexpr指针无法指向。
constexpr const int *p = &i;                    /*p是常量指针,指向  整型常量i*/
constexpr int *p1 = &j;                       //p1是常量指针,指向  整数j(非常量)

constexpr函数

​ 指能用于常量表达式的函数。该函数要遵循规定:函数的返回类型及所有形参的类型都得是字面值类型(声明constexpr变量时用到的类型),并且函数体中必须有且只有一条return语句

constexpr int new_sz() { return 42; }//constexpr函数
constexpr int foo = new_sz();
//在对变量foo初始化时,编译器把对constexpr函数的调用替换成其结果值。为了能在编译过程中随时展开,constexpr函数被隐式地指定为内联函数。

​ constexpr函数体内也可以包含其他语句,只要这些语句在运行时不执行任何操作即可。如空语句、类型别名、using声明。

需要注意的是,我们允许constexpr函数的返回值并非一个常量???

​ 这里需要弄清楚字面值类型的意义。。。

//如果arg是常量表达式,则scale(arg)也是常量表达式
constexpr size_t scale(size_t cnt){ return new_sz() * cnt; }

//当scale的实参是常量表达式时,它的表达式也是常量表达式,反之则不然
int arr[scale(2)];	//正确:scale(2)是常量表达式
int i = 2;			//i不是常量表达式
int a2[scale(i)];	//错误:scale(i)不是常量表达式

注意,我们要把内联函数和constexpr函数定义在头文件中

posted @ 2020-06-11 20:04  Rser_ljw  阅读(185)  评论(0编辑  收藏