常量表达式函数

要求:

  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. configparse模块和hashlib模块

    # import configparser # # config = configparser.ConfigParser() #config = {} # config['DEFAULT'] = {' ...

  2. win 10 kms 激活 后 火狐 上 https 网站 报错

    原因: 系统导入了未知的根证书 影响:?? 解决方法: http://mozilla.com.cn/thread-374897-1-1.html

  3. Excel中的数据与DataSet的互换

    using System;using System.Collections.Generic;using System.Data;using System.Drawing;using System.IO ...

  4. 3.1 MathType上标位置调整的两种方法

    具体操作步骤如下: 1.打开MathType窗口后在工作区域中编辑好公式. 2.调整上标位置有两种方法: (1)选中要调整的上标,按下“Ctrl+↑,Ctrl+↓,Ctrl+←,Ctrl+→”进行调整 ...

  5. python3中的编码

    python2字符串编码存在的问题: 使用 ASCII 码作为默认编码方式,对中文处理不友好 把字符串分为 unicode 和 str 两种类型,将unicode作为唯一内码,误导开发者 python ...

  6. Centos7创建CA和申请证书 转自https://www.cnblogs.com/mingzhang/p/8949541.html

    Centos7.3创建CA和申请证书 openssl 的配置文件:/etc/pki/tls/openssl.cnf 重要参数配置路径 dir   = /etc/pki/CA               ...

  7. Django2.0资料

    The Django Book 2.0 中文版:点击下载 Django课件和代码:点击下载

  8. 黄聪:C#使用Application.Restart重启程序出错解决办法

    调用 Application.Restart重启程序出错 解决办法,就是给程序的.exe文件,加上下面的设置

  9. C现代编程

    1.C语言没有像面向对象语言一样提供访问控制的功能,无法实现数据隐藏,可以通过规定成员命名来规避这个问题,例如不允许直接访问的成员以“_”开头. 2.模板模式,利用函数指针,抽离固有代码,差异代码放到 ...

  10. SAX解析与DOM解析

    SAX解析实例:http://www.iteye.com/topic/763895 Java Sax解析是按照xml文件的顺序一步一步的来解析,在解析xml文件之前,我们要先了解xml文件的节点的种类 ...