C++11关键字constexpr看这篇就够了
一、在普通函数中的使用
例如下面的代码,
数组的大小必须是常量,在声明数组array时,用函数返回值,此时会报错:
error C2131: 表达式的计算结果不是常数
note: 对未定义的函数或为未声明为“constexpr”的函数的调用导致了故障
用constexpr关键字可以解决这种问题,在GetLen函数前加constexpr声明,代码如下:
当然,constexpr修饰的函数也有一定的限制:
(1)函数体尽量只包含一个return语句,多个可能会编译出错;
(2)函数体可以包含其他语句,但是不能是运行期语句,只能是编译期语句;
编译器会将constexpr函数视为内联函数!所以在编译时若能求出其值,则会把函数调用替换成结果值。
二、在类的构造函数中也可以使用constexpr关键字
constexpr还能修饰类的构造函数,即保证传递给该构造函数的所有参数都是constexpr,那么产生的对象的所有成员都是constexpr。该对象是constexpr对象了,可用于只使用constexpr的场合。
注意constexpr构造函数的函数体必须为空,所有成员变量的初始化都放到初始化列表中。
代码如下:
#include <iostream>
using namespace std;
class Test
{
public:
constexpr Test(int num1, int num2) : m_num1(num1), m_num2(num2)
{
}
public:
int m_num1;
int m_num2;
};
int main(void)
{
constexpr Test t1(1, 2);
enum e
{
x = t1.m_num1,
y = t1.m_num2
};
return 0;
}
如果在构造函数中加点代码,就会编译报错,如下:
三、const和constexpr对指针的修饰有什么差别呢?
(1)const 和 constexpr 变量之间的主要区别在于:const 变量的初始化可以延迟到运行时,而 constexpr 变量必须在编译时进行初始化。所有 constexpr 变量均为常量,因此必须使用常量表达式初始化。
(2)constexpr和指针
在使用const时,如果关键字const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针本身是常量;如果出现在星号两边,表示被指物和指针两者都是常量。
与const不同,在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指对象无关。
constexpr是一种很强的约束,更好的保证程序的正确定语义不被破坏;编译器可以对constexper代码进行非常大的优化,例如:将用到的constexpr表达式直接替换成结果, 相比宏来说没有额外的开销。
代码:
#include <iostream>
using namespace std;
int g_tempA = 4;
const int g_conTempA = 4;
constexpr int g_conexprTempA = 4;
int main(void)
{
int tempA = 4;
const int conTempA = 4;
constexpr int conexprTempA = 4;
/*1.正常运行,编译通过*/
const int *conptrA = &tempA;
const int *conptrB = &conTempA;
const int *conptrC = &conexprTempA;
/*2.局部变量的地址要运行时才能确认,故不能在编译期决定,编译不过*/
constexpr int *conexprPtrA = &tempA;
constexpr int *conexprPtrB = &conTempA;
constexpr int *conexprPtrC = &conexprTempA;
/*3.第一个通过,后面两个不过,因为constexpr int *所限定的是指针是常量,故不能将常量的地址赋给顶层const*/
constexpr int *conexprPtrD = &g_tempA;
constexpr int *conexprPtrE = &g_conTempA;
constexpr int *conexprPtrF = &g_conexprTempA;
/*4.局部变量的地址要运行时才能确认,故不能在编译期决定,编译不过*/
constexpr const int *conexprConPtrA = &tempA;
constexpr const int *conexprConPtrB = &conTempA;
constexpr const int *conexprConPtrC = &conexprTempA;
/*5.正常运行,编译通过*/
constexpr const int *conexprConPtrD = &g_tempA;
constexpr const int *conexprConPtrE = &g_conTempA;
constexpr const int *conexprConPtrF = &g_conexprTempA;
return 0;
}
四、对引用的修饰
代码如下:
#include <iostream>
using namespace std;
int g_tempA = 4;
const int g_conTempA = 4;
constexpr int g_conexprTempA = 4;
int main(void)
{
int tempA = 4;
const int conTempA = 4;
constexpr int conexprTempA = 4;
/*1.正常运行,编译通过*/
const int &conptrA = tempA;
const int &conptrB = conTempA;
const int &conptrC = conexprTempA;
/*2.有两个问题:一是引用到局部变量,不能再编译器确定;二是conexprPtrB和conexprPtrC应该为constexpr const类型,编译不过*/
constexpr int &conexprPtrA = tempA;
constexpr int &conexprPtrB = conTempA;
constexpr int &conexprPtrC = conexprTempA;
/*3.第一个编译通过,后两个不通过,原因是因为conexprPtrE和conexprPtrF应该为constexpr const类型*/
constexpr int &conexprPtrD = g_tempA;
constexpr int &conexprPtrE = g_conTempA;
constexpr int &conexprPtrF = g_conexprTempA;
/*4.正常运行,编译通过*/
constexpr const int &conexprConPtrD = g_tempA;
constexpr const int &conexprConPtrE = g_conTempA;
constexpr const int &conexprConPtrF = g_conexprTempA;
return 0;
}
简单的说constexpr所引用的对象必须在编译期就决定地址。还有一个奇葩的地方就是可以通过上例conexprPtrD来修改g_tempA的值,也就是说constexpr修饰的引用不是常量,如果要确保其实常量引用需要constexpr const来修饰。
以上是C++ 11 constexpr的简单应用,要深入学好C++,需要长期的训练,刻意练习。
from:https://blog.csdn.net/yao_hou/article/details/109301290