C++ 特性constexpr

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值