#include <iostream>
/*
在大多数情况下,const描述的都是一些“运行时常量性”概念
即具有运行时数据的不可更改性。不过有的时候,我们需要的
却是编译时期的常量性,这是const关键字无法保证的;
*/
// 使用const关键字修饰函数返回类型,在数组定义、匿名枚举、switch 的
// case中都会报错,这些语句需要的都是编译时期的常量,而const修饰的函数返回值
// 只保证了运行时期其值不被更改;
const int GetConst() {return 1;}
// void Constless(int cond) {
// int arr[GetConst()] = {0} // error
// enum { e1 = GetConst(), e2}; // error
// switch(code) {
// case GetConst():// error
// break;
// default:
// break;
// }
// }
// C++11 提供了 constexpr 让用户显式的声明函数或对象构造函数在编译期会成为常量表达式
// 在函数返回类型前加上constexpr关键字(常量表达式-const expression),编译器以在
// 编译时期对fool_constexpr函数进行值计算,从而将其视为编译时期常量
constexpr int fool_constexpr()
{
return 10;
}
void test1()
{
// C++array数组长度必须是常量表达式
int array[10];
int len1 = 10;
int array1[len1]; // 非法,len1长度不是常量表达式
const int len2 = len1 + 10;
char array2[len2]; // 非法, len2是常数,但不是常量表达式,可能部分编译器成功
constexpr int len3 = 1 + 2 + 3;
char array3[len3]; // 合法
char array4[GetConst() + 2]; // 非法
// constexpr解决函数运行期间
char array5[fool_constexpr() + 2]; // 合法,有时遇到这样场景,数组长度来之某个函数返回值,需要用到constexpr
}
// constexpr常量表达式函数运用需要有严格的限制
/*
1.函数体只有单一的return 语句(using,typedef,static_assert等除外);
2.函数必须有返回值(不能是void函数);
3.在使用前必须被定义实现;
4.return 返回的表达式不能使用非常量表达式函数、全局数据,且必须是一个常量表达式;
*/
constexpr int fool() {
int x = 10; // 和第1个规则有出入?
return x;
}
constexpr void voidFool(){}
// constexpr int DeclareFool();// 只有声明没有实现,编译时期需要调用进行计算的
int NoConstExprFunc(){return 1;}
// constexpr int NestedCall() {
// return NoConstExprFunc(); // 常量表达式中不能使用非常量表达式函数
// }
void test2()
{
int arr[fool()] = {0};
for (const auto it: arr) {std::cout<<it<<std::endl;}
//enum {e1= voidFool(), e2};// error
//int arr1[DeclareFool()] = {0}; // error
}
// constexpr关键字不能直接用来修饰自定义类型
// constexpr struct Type{int i;}; // error, struct cannot be marked constexpr
// 但可以用来修饰类构造函数,但
// 函数体必须为空和初始化列表只能由常量表达式赋值
struct MyType{
constexpr MyType(int i_):i(i_){}
int i;
};
// int ConstExprfool(){
// return 1;
// }
// struct MyFool{
// constexpr MyFool():i(ConstExprfool()){} // ConstExprfool 必须是constexpr返回值类型
// int i;
// };
void test3()
{
int i = 0;
//constexpr MyType t = {i}; // error,must be init by a constant expression
constexpr int ci = 0;
constexpr MyType t = {ci}; //
}
// constexpr不能用于类的virtual修饰的成员函数,因为
// virtual函数是运行时动态调用的与constexpr编译时计算值是相冲突的
// constexpr用在模板函数中
// NoLiteral构造函数不是constexpr表达式
struct NoLiteral {
//constexpr NoLiteral(int i_):i(i_){}
int i;
};
// 当constexpr修饰模板函数时,若模板实例化结果不满足常量
// 表达式, 则constexpr会被自动忽略
template<typename T>
constexpr T GeneratorObj(T t) {
return t;
}
void test4()
{
//constexpr NoLiteral n1(1);
NoLiteral n1(1);
// n2必须被constexpr表达式初始化
constexpr NoLiteral n2 = GeneratorObj<NoLiteral>(n1);// error,reutrn non-constexpr NoLiteral object
}
// c++14在c++11的constexpr引入了if constexpr控制流,编译时确认分支
template<typename T>
auto printTypeInfo(const T& t){
if constexpr (std::is_integral<T>::value) {
return t+1;
}
else {
return t+1.1;
}
}
void Test5 (){
printTypeInfo(1);
/*展开
printTypeInfo(const T& t){
return t+1;
}
*/
printTypeInfo(1.1);
/*
printTypeInfo(const T& t){
return t+1.1;
}
*/
}
int main()
{
test2();
return 0;
}
C++ 特性constexpr
于 2021-09-11 17:51:27 首次发布