一、constexpr意义
将变量声明为constexpr类型以便由编译器来验证变量是否是一个常量表达式(不会改变,在编译过程中就能得到计算结果的表达式)。是一种比const更强的约束,这样可以得到更好的效率和安全性。
二、constexpr用法
1.修饰函数
/*1.如果size在编译时能确定,那么返回值就可以是constexpr,编译通过*/
constexpr int getSizeA(int size)
{
return 4*size;
}
/*2.编译通过,有告警:在constexpr中定义变量*/
constexpr int getSizeB(int size)
{
int index = 0;
return 4;
}
/*3.编译通过,有告警:在constexpr中定义变量(这个有点迷糊)*/
constexpr int getSizeC(int size)
{
constexpr int index = 0;
return 4;
}
/*4.编译通过,有告警:使用了if语句(使用switch也会告警)*/
constexpr int getSizeD(int size)
{
if(0)
{}
return 4;
}
/*5.定义变量并且没有初始化,编译不过*/
constexpr int getSizeE(int size)
{
int index;
return 4;
}
/*6.rand()为运行期函数,不能在编译期确定,编译不过*/
constexpr int getSizeF(int size)
{
return 4*rand();
}
/*7.使用了for,编译不过*/
constexpr int getSizeG(int size)
{
for(;0;)
{}
return 4*rand();
}
总结:constexpr修饰的函数,不能依赖任何运行期的信息,不要定义任何变量常量,并且必须尽量简单,要不就会编译不过或告警(坑)。
2.修饰类型
int tempA;
cin>>tempA;
const int ctempA = 4;
const int ctempB = tempA;
/*1.可以再编译器确定,编译通过*/
constexpr int conexprA = 4;
constexpr int conexprB = conexprA + 1;
constexpr int conexprC = getSizeA(conexprA);
constexpr int conexprD = ctempA;
/*2.不能在编译期决定,编译不过*/
constexpr int conexprE = tempA;
constexpr int conexprF = ctempB;
总结:constexpr修饰的常量必须在编译期确定值,上面的例子也体现出了和const之间的差别。const既可以在编译期确定如ctempA,也可以在运行期确定如ctempB,使用范围更广。还有一点constexpr只能修饰字面值类型如算数类型、引用类型、指针以及后面介绍的字面值常量类。
3.修饰指针
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;
}
总结:constexpr指针不能用局部变量赋值,const指针可以;constexpr指针里是顶层const,即指针是常量,而不是所指向的类型是常量,如果要指向的类型也为常量,要用constexpr const来修饰。
4.修饰引用
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来修饰。
5.修饰类(未完待续)
原文链接: https://www.cnblogs.com/cauchy007/p/4966067.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/224513
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!