C++11特性(11):常量表达式(值)

#include <iostream>
#include <iterator> //for ostream_iterator
 
//常量表达式
//1、运行时常量性与编译时常量性即const与constexpr
const int GetConst(){ return 1; } //运行时常量
constexpr int GetConstexpr(){ return 1; } //编译时常量
 
//constexpt表达式函数的要求:
//1、函数体只用单一的return返回语句
//2、函数必须有返回值,不能是void函数
//3、在使用前必须已有定义
//4、return返回语句表达式中不能使用非常量表达式的函数、全局数据,且必须是一个常量表达式
 
//要求3:
constexpr int f();     //constexpr表达式函数声明
int a = f();
const int b = f();
constexpr int c = f(); //error,在使用前必须有定义
constexpr int f(){ return 1; } //constexpr表达式函数定义
constexpr int e = f();     //ok,使用前已定义
 
//要求4:
constexpr int g(){ return GetConst(); } //error,无法在return返回语句中使用非常量表达式的函数
constexpr int h(){ return GetConstexpr(); }     //ok,return语句中是一个常量表达式
int p = 3;
constexpr int m(){ return p; } //error,常量表达式函数中无法返回全局数据

//常量表达式值:使用constexpr修饰的变量即为常量表达式值,
//常量表达式值必须被一个常量表达式赋值,在使用前必须被初始化
constexpr int aa = 1;
constexpr int bb = aa;    //ok
 
//对于自定义的数据类型,要想成为常量表达式值的时候,需要自定义常量构造函数,只需在构造函数前加上constexpr关键字
//要求约束:
//1、函数体必须为空
//2、有成员变量,必须要初始化
//3、初始化列表只能由常量表达式来赋值
class ConstexprClass
{
public:
     constexpr ConstexprClass(int x) :i(x){}
     int i;
};
 
class Date
{
public:
     constexpr Date(int y, int m, int d) :year(y), month(m), day(d){}
     constexpr int GetYear(){ return year; }
     constexpr int GetMonth(){ return month; }
     constexpr int GetDay(){ return day; }
private:
     int year;
     int month;
     int day;
};
 
//常量表达式可以用于模版函数
//当声明为常量表达式的模版函数后,如果某个该模版函数的实例化结果不满足常量表达式需求的话,constexpr被自动忽略
struct NotLiteral
{
     NotLiteral(){ i = 5; }
     int i;
};
struct Literal
{
     constexpr Literal(){}
};
 
template<typename T>
constexpr T ConstExprFun(T t)
{
     return t;
}
 
//constexpr递归问题
constexpr int Fib(int n)
{
     return (n == 1 || n == 2 ? 1 : (Fib(n - 1) + Fib(n - 2)));
}
//模板元
template<long num = 10>
struct Fibo
{
     static const long result = Fibo<num - 1>::result + Fibo<num - 2>::result;
};
template<>
struct Fibo<0>{ static const long result = 0; };
template<>
struct Fibo<1>{ static const long result = 1; };
template<>
struct Fibo<2>{ static const long result = 1; };

int main()
{
     int arr[GetConst()] = { 0 };    //无法使用运行时常量来初始化数组
     enum{ e1 = GetConst(), e2 };    //也无法使用运行时常量作为枚举值
     int arr2[GetConstexpr()] = { 0 };    //ok
     constexpr ConstexprClass mc(0);     //必须使用常量表达式赋值
     //constexpr ConstexprClass mc = { 0 };等价上一条
     //constexpr ConstexprClass mc{ 0 }; 等价上一条
 
     //疑问? 
     //gcc-5.1报错:"error: passing 'const Date' as 'this' argument discards qualifiers [-fpermissive]"
     constexpr Date d(1990, 11, 28);
     constexpr int year = d.GetYear();
     constexpr int month = d.GetMonth();
     constexpr int day = d.GetDay();
     std::cout << "year:" << year << std::endl
          << "month" << month << std::endl
          << "day" << day << std::endl;

     //结构体NotLiteral不是定义了常量表达式构造函数的类型,因此不能够声明为常量表达式值
     //而模版函数一旦以NotLiteral作为参数,那么其constexpr关键字就会被忽略
     NotLiteral nl;
     NotLiteral nl1 = ConstExprFun(nl);
     constexpr NotLiteral nl2 = ConstExprFun(nl);    //编译失败
     constexpr int a = ConstExprFun(1);
     constexpr Literal l1;
     Literal l2 = ConstExprFun(l1);    //ok
     constexpr Literal l3 = ConstExprFun(l1);    //ok
 
    //constexpr函数递归
     int fibs[] = { Fib(11), Fib(12), Fib(13), Fib(14), Fib(15) };
     std::copy(std::begin(fibs), std::end(fibs),
              std::ostream_iterator<int>(std::cout, " "));    //89 144 233 377 610 
 
     std::cout << std::endl;
     //使用模板元实现递归编程
     int fibs2[] = { Fibo<11>::result, Fibo<12>::result, 
                                    Fibo<13>::result, Fibo<14>::result, Fibo<15>::result };
     std::copy(std::begin(fibs2), std::end(fibs2),
              std::ostream_iterator<int>(std::cout, " "));    //89 144 233 377 610
     return 0;
}

====================打个广告,欢迎关注====================

QQ:412425870
csdn博客:
http://blog.youkuaiyun.com/caychen
码云:
https://gitee.com/caychen/
github:
https://github.com/caychen

点击群号或者扫描二维码即可加入QQ群:

328243383(1群)



点击群号或者扫描二维码即可加入QQ群:

180479701(2群)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值