常量表达式函数

要求:

  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. python 进程池的使用和坑

    from multiprocessing import Pool,Process import time,os def Foo(a):#创建函数 time.sleep(2) print('in the ...

  2. C++学习(三十八)(C语言部分)之 排序(冒泡 选择 插入 快排)

    算法是解决一类问题的方法排序算法 根据元素大小关系排序 从小到大 从大到小冒泡 选择 插入 快排希尔排序 归并排序 堆排序 冒泡排序 从头到尾比较 每一轮将最大的数沉底 或者最小数字上浮 选择排序 1 ...

  3. JDK下载与安装、 Eclipse下载与使用、 Tomcat下载与使用、 MySQL安装与使用

    前言 本文将介绍JDK的下载与安装,eclipse的下载与使用,Tomcat的下载与使用,MySQL的安装与使用. JDK下载与安装 一.JRE与JDK介绍 java是当前比较流行的一种编程语言,当我 ...

  4. oracle左关联+号表示方式

    1.emp表和dept表 2.emp表中empno为8888的这条数据,没有部门编号,以emp表为主表,左关联查询部门信息sql语句如下: select * from emp e,dept d whe ...

  5. 转"container of()函数简介"链接地址

    https://blog.csdn.net/s2603898260/article/details/79371024 提示关键字: 指针0的使用 typeof的使用

  6. ScriptManager 发送错误到客户端

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx. ...

  7. 【spring】之基于注解@ComponentScan的一些使用

    基于xml形式ComponentScan的使用如下 <context:component-scan base-package="com.luna" use-default-f ...

  8. PAT 乙级 1091 N-自守数 (15 分)

    1091 N-自守数 (15 分) 如果某个数 K 的平方乘以 N 以后,结果的末尾几位数等于 K,那么就称这个数为“N-自守数”.例如 3×92​2​​=25392,而 25392 的末尾两位正好是 ...

  9. SPI、I2C、UART、I2S、GPIO、SDIO、CAN 简介

    转自http://sanwen.net/a/fmxnjoo.html SPI.I2C.UART.I2S.GPIO.SDIO.CAN,看这篇就够了 总线 总线,总要陷进里面.这世界上的信号都一样,但是总 ...

  10. docker 批量删除

    杀死所有正在运行的容器docker kill $(docker ps -a -q) 删除所有已经停止的容器docker rm $(docker ps -a -q) 删除所有未打 dangling 标签 ...