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函数定义在头文件中。