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的区别

C++中 const和constexpr的区别

C++中 const和constexpr的区别

当 const 有效时,为啥我不能声明 constexpr local?

const 和 constexpr