constexpr介绍以及与const的区别
Posted 非晚非晚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了constexpr介绍以及与const的区别相关的知识,希望对你有一定的参考价值。
文章目录
1. 常量表达式
所谓常量表达式,指的就是由多个(≥1)常量组成的表达式。换句话说,如果表达式中的成员都是常量,那么该表达式就是一个常量表达式。也就是说一旦常量表达式一旦确定,它的值是不允许被改变
。
C++ 程序的执行过程大致为:编译、链接、运行这 3 个阶段。而常量表达式与非常量表达式的执行阶段是不一样的。
- 非常量表达式只能在程序
运行阶段
计算出结果;- 而常量表达式的计算往往发生在程序的
编译阶段
。
所以常量表达式可以极大提高程序的执行效率,因为常量表达式只需要在编译阶段计算一次,节省了每次程序运行时都需要计算一次的时间。c++11中提供了constexpr关键字来指定常量表达式。C++ 11 标准中,constexpr 可用于修饰普通变量、函数(包括模板函数)以及类的构造函数。
2. constexpr
2.1 constexpr修饰常量
C++11 标准中,定义常量或常量表达式时可以用constexpr修饰,从而使该变量获得在编译阶段即可计算出结果的能力。
#include <iostream>
using namespace std;
int main()
constexpr int num = 1 + 2 + 3;
int a[num] = 1,2,3,4,5,6;
cout<< a[1] << endl;//2
return 0;
2.2 constexpr修饰函数
constexpr 还可以用于修饰函数的返回值,这样的函数又称为常量表达式函数
。一个函数想要成为常量表达式函数,要同时具备如下4个条件:
条件一
:整个函数的函数体中,除了可以包含 using 指令、typedef 语句以及 static_assert 断言外,只能包含一条 return 返回语句
。
- 错误示例
下列代码包含多条语句,无法编译通过。
constexpr int display(int x)
int ret = 1 + 2 + x;
return ret;
- 正确示例
constexpr int display(int x)
//可以添加 using 执行、typedef 语句以及 static_assert 断言
return 1 + 2 + x;
条件二
:该函数必须有返回值,即函数的返回值类型不能是 void。
- 错误示例
constexpr void display()
//函数体
条件三
:使用函数之前,必须先定义。
我们知道,函数的使用分为“声明”和“定义”两部分,普通的函数调用只需要提前写好该函数的声明部分即可(函数的定义部分可以放在调用位置之后甚至其它文件中),但常量表达式函数在使用前,必须要有该函数的定义
。
- 正确示例
#include <iostream>
using namespace std;
//普通函数的声明
int noconst_dis(int x);
//常量表达式函数的声明
constexpr int display(int x);
//常量表达式函数的定义
constexpr int display(int x)
return 1 + 2 + x;
int main()
//调用常量表达式函数
int a[display(3)] = 1,2,3,4 ;
cout << a[2] << endl;
//调用普通函数
cout << noconst_dis(3) << endl;
return 0;
//普通函数的定义
int noconst_dis(int x)
return 1 + 2 + x;
条件四
:return 返回的表达式必须是常量表达式
- 错误示例
#include <iostream>
using namespace std;
int num = 3;
constexpr int display(int x)
return num + x;//错误,num非常量
int main()
//调用常量表达式函数
int a[display(3)] = 1,2,3,4 ;
return 0;
2.3 constexpr修饰类的构造函数
对于 C++ 内置类型的数据,可以直接用 constexpr 修饰,但如果是自定义的数据类型(用 struct 或者 class 实现),不可以直接使用constexpr 修饰,但可以使用constexpr修饰它的构造函数。
- 错误示例
此程序是无法通过编译的,编译器会抛出“constexpr不能修饰自定义类型”的异常。
#include <iostream>
using namespace std;
//自定义类型的定义
constexpr struct myType
const char* name;
int age;
//其它结构体成员
;
int main()
constexpr struct myType mt "zhangsan", 10 ;
cout << mt.name << " " << mt.age << endl;
return 0;
- 正确示例
#include <iostream>
using namespace std;
//自定义类型的定义
struct myType
constexpr myType(char *name,int age):name(name),age(age);
const char* name;
int age;
//其它结构体成员
;
int main()
constexpr struct myType mt "zhangsan", 10 ;
cout << mt.name << " " << mt.age << endl;
return 0;
2.4 constexpr修饰模板函数
C++11 语法中,constexpr 可以修饰模板函数。C++11 标准规定,如果 constexpr 修饰的模板函数实例化结果不满足常量表达式函数的要求,则 constexpr 会被自动忽略,即该函数就等同于一个普通函数
。
#include <iostream>
using namespace std;
//自定义类型的定义
struct myType
const char* name;
int age;
//其它结构体成员
;
//模板函数
template<typename T>
constexpr T dispaly(T t)
return t;
int main()
struct myType stu"zhangsan",10;
//普通函数
struct myType ret = dispaly(stu);
cout << ret.name << " " << ret.age << endl;
//常量表达式函数
constexpr int ret1 = dispaly(10);
cout << ret1 << endl;
return 0;
3. constexpr与const的区别
const表示只读变量,实际使用时,它有两种语义。
语义一
:func_1中的“const int x”强调的x是一个只读变量
,其本质仍为变量,无法用来初始化 array 容器。语义二
:func_2中的“const int x”表明 x 是一个只读变量的同时,x 还是一个值为 5 的常量
,所以可以用来初始化 array 容器。
#include <iostream>
#include <array>
using namespace std;
void func_1(const int x)
array <int,x> myarr1,2,3,4,5;//错误,x是只读的变量,它的值需要在运行阶段确定
cout << myarr[1] << endl;
void func_2()
const int x = 5;
array <int,x> myarr1,2,3,4,5;//正确,已经初始化了,编译阶段已经确定x的值
cout << myarr[1] << endl;
int main()
func_1(5);
func_2();
C++ 11标准中,为了解决 const 关键字的双重语义问题,保留了 const 表示“只读”的语义,而将“常量”的语义划分给了新添加的 constexpr 关键字。因此 C++11 标准中,建议将 const 和 constexpr 的功能区分开,即凡是表达“只读”语义的场景都使用 const,表达“常量”语义的场景都使用 constexpr。
有读者可能会问,“只读”不就意味着其不能被修改吗?答案是否定的,“只读”和“不允许被修改”之间并没有必然的联系,举个例子:
#include <iostream>
using namespace std;
int main()
int a = 10;
const int & con_b = a;
cout << con_b << endl;
a = 20;
cout << con_b << endl;
输出:
10
20
可以看到,程序中用 const 修饰了 con_b 变量,表示该变量“只读”,即无法通过变量自身去修改自己的值。但这并不意味着 con_b 的值不能借助其它变量间接改变,通过改变 a 的值就可以使 con_b 的值发生变化。
在大部分实际场景中,const 和 constexpr 是可以混用的,例如:
const int a = 5 + 4;
constexpr int a = 5 + 4;
它们是完全等价的,都可以在程序的编译阶段计算出结果。但在某些场景中,必须明确使用 constexpr,例如:
#include <iostream>
#include <array>
using namespace std;
constexpr int sqr1(int arg)
return arg*arg;
const int sqr2(int arg)
return arg*arg;
int main()
array<int,sqr1(10)> mylist1;//可以,因为sqr1时constexpr函数
array<int,sqr2(10)> mylist1;//不可以,因为sqr2不是constexpr函数
return 0;
参考:
http://c.biancheng.net/view/7781.html
http://c.biancheng.net/view/7807.html
以上是关于constexpr介绍以及与const的区别的主要内容,如果未能解决你的问题,请参考以下文章
C++11之常量表达式(const与constexpr的区别)
C++11新特性:17—— C++11 constexpr和const的区别