常量表达式函数

要求:

  1. 函数体内只有单一的return返回语句

    例如:
constexpr int data()
{
const int i=1; //含有除了return以外的语句
return i;
}

在c++11中是无法通过编译的。

但使用不会产生实际代码的语句是可以的,例如static_assert()

2. 函数必须返回值

例如constexpr void f(){}无法通过编译的,因为无法获得常量的常量表达式是不被认可的。

3. 在使用前必须已有定义

constexpr int f();
constexpr int c=f(); //无法通过编译
constexpr int f(){return 1;}
  1. return返回语句表达式中不能使用非常量表达式的函数、全局数据,且必须是一个常量表达式。
const int e(){return 1;}
constexpr int g(){return e();} //编译错误,使用了非常量表达式的函数

常量表达式值

const int i=1;
constexpr int j=1;

两者在大多数情况下没有区别,但如果i在全局名称空间中,编译器一定会为i产生数据。而对于j,如果不是有代码显式地使用了它的地址,编译器可以选择不为它生成数据,而仅将其当作编译时期的值。

在C++11中constexpr是不能用于自定义类型的,例如:

constexpr struct MyType{int i;}
constexpr MyType mt={0};

将无法通过编译。正确的做法是,定义自定义常量构造函数:

struct MyType
{
constexpr MyType(int x):i(x){}
int i;
};
constexpr MyType mt = { 0 };

常量表达式的构造函数也有使用上的约束:

  1. 函数体必须为空
  2. 初始化列表只能由常量表达式来赋值。

此外,在C++11中,不允许常量表达式作用于virtual的成员函数。vitual是运行时的行为,与编译期计算的constexpr的意义是冲突的。

常量表达式的构造函数也可以用于非常量表达式中的类型构造,且无法重写。

其他应用

模板函数

常量表达式是可以用于模板函数的,不过由于模板中类型的不确定性,所以模板函数是否会被实例化为一个能够满足编译时常量性的版本通常也是未知的。C++11标准规定:当声明为常量表达式的模板函数后,而某个该模板函数的实例化结果不满足常量表达式的需求的话,constexpr会被自动忽略。该实例化后的函数将成为一个普通函数。

例如:

struct NotLiteral
{
NotLiteral(){i=5;}
int i;
};
NotListeral nl; template<class T>
constexpr T ConstExp(T t)
{
return t;
}
void g()
{
NotLiteral nl;
NotLiteral nl1=ConstExp(nl);
constexpr NotLiteral nl2=ConstExp(nl); //无法编译
constexpr int a=ConstExp(1); //OK
}

代码中NotLiteral不是一个定义了常量表达式构造函数的类型,因此不能够声明为常量表达式值。而模板函数ConstExp一旦以NotLiteral为参数的话,那么其constexpr关键字将被忽略。

递归

常量表达式支持至少512层的递归,可以在编译期充当“计算器”。

constexpr int Fibonacci(int n)
{
return (n == 1) ? 1 : ((n == 2) ? 2 : Fibonacci(n - 1) + Fibonacci(n - 2));
} Fibonacci(12);

然而并不是使用了constexpr,编译器就一定会在编译期间对常量表达式函数进行值计算。标准只是定义了可以用于编译时进行值计算的常量表达式的定义,却没有强制要求编译器一定在编译时进行值计算。(经反汇编,上述代码在vs2017debug下未在编译期计算出结果)所以编译器通过一些手段绕过代码的语法,仍然做运行时的调用,这样也是符合C++11的。

内容摘自《深入理解C++11》

C++11 constexpr常量表达式的更多相关文章

  1. C++11特性——变量部分(using类型别名、constexpr常量表达式、auto类型推断、nullptr空指针等)

    #include <iostream> using namespace std; int main() { using cullptr = const unsigned long long ...

  2. C++11常量表达式

    [C++11之常量表达式] 关键字:constexpr: 中文学名:常量表达式. constexpr用于把运行期计算放置在编译期. 使用constexpr有3个限制: 1.函数中只能有一个return ...

  3. 常量表达式和constexpr(c++11)

    常量表达式 常量表达式是指值不会改变且在编译阶段就能得到计算结果的表达式(两点要求) ; //是常量表达式 ; //是常量表达式 "; const int siz=s.size(); //不 ...

  4. constexpr与常量表达式(c++11标准)

    关键字 constexpr 是C++11中引入的关键字,是指值不会改变并且在编译过程中就得到计算结果的表达式.(运行中得到结果的不能成为常量表达式,比如变量). 声明为constexpr的变量一定是一 ...

  5. C++常量表达式、const、constexpr(C++11新增)的区别

    常量表达式是指值不会改变且在编译过程中就能够得到计算结果的表达式,能在编译时求值的表达式. 程序先编译再运行:  在编译阶段, 编译器将在编译过程中把用到该常量的地方都全都替换为 常量的值. 但是常量 ...

  6. constexpr和常量表达式

    常量表达式:值不会改变并且在编译过程就能得到计算结果的表达式. 字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式. 一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同 ...

  7. constexpr和常量表达式的注意事项

    1.常量表达式,是指其值不可改变,且在编译阶段就已经得出计算结果的表达式,例如字面值就是常量表达式. 2.判断是否是常量表达式,要关注数据类型是否是const类型,初始值是否是在编译阶段就得到的. 3 ...

  8. 第8课 常量表达式(constexpr)

    一. const 和constexpr的区别 (一)修饰变量时,const为“运行期常量”,即运行期数据是只读的.而constexpr为“编译期”常量,这是const无法保证的.两者都是对象和函数接口 ...

  9. c++11 常量表达式

    c++11 常量表达式 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #inclu ...

随机推荐

  1. Java基于opencv实现图像数字识别(一)

    Java基于opencv实现图像数字识别(一) 最近分到了一个任务,要做数字识别,我分配到的任务是把数字一个个的分开:当时一脸懵逼,直接百度java如何分割图片中的数字,然后就百度到了用Buffere ...

  2. zabbix的自动发现、自定义添加监控项目、配置邮件告警

    1.zabbix的自动发现这里的自动发现,所显示出来的是规则的上自动了现 然后 可以对其内容进行相关的配制,如时间或周期 注意:对于单个主机的规则,可以自行添加或删除, 但对于已经添加好了的规则,若需 ...

  3. 使用deb 打包开发的postgres extension

    昨天写过一个使用rpm 打包分发pg 扩展的demo,今天使用deb 进行打包分发,同时使用checkinstall 生成我们的deb包 安装deb 依赖 sudo apt-get install c ...

  4. docker安装solr集群5.3.1

    docker-compose.yml: version: '3' services: zookeeper-A: image: zookeeper:3.4.11 ports: - "12181 ...

  5. linux-linnode满了的提示

    线上有一台web服务器磁盘检测告警了,提示空间不足,登到服务器查看 <ignore_js_op> touch:cannot touch `furm.html': No space left ...

  6. 怎样生成一个顶点迭代器(MItMeshVertex)

    最近修改一个maya中的jlCollisionDeformer工具,该工具有一个明显不足,变形后顶点分布太乱,无法满足生产需求.于是考虑对该变形后的顶点进行平滑处理.既然要做平滑处理就要获取当前点及与 ...

  7. ByteToByte64String、Base64StringToBytes

    public string ByteToByte64String(byte[] bytes) { return Convert.ToBase64String(bytes); } public byte ...

  8. phpcms调用语句

    title 标题:url 链接地址:thumb缩略图 :先调用moreinfo="1"  content 内容: {php list($copyfrom) = explode('| ...

  9. 安装zookeeper遇到的问题

    最近在安装zookeeper的时候遇到了一个问题:调用./zkServer.sh start之后,使用命令telnet localhost 2181,显示访问被拒绝.然后使用netstat查看监听21 ...

  10. google的protobuf简单介绍

    google的protobuf是一种轻便高效的结构化数据存储格式,在通信协议和数据存储等领域中使用比较多.protobuf对于结构中的每个成员,会提供set系列函数和get系列函数. 但是,对于使用来 ...