constexpr和常量表达式

常量表达式(const expression)是指值不会改变并且在编译过程就能得到计算结果的表达式。显然,字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。后面将会提到,C++语言中有几种情况下是要用到常量表达式的。

一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定,例如:

  1. const int max_files = 20;       // max_files是常量表达式
  2. const int limit = max_files + 1;    // limit是常量表达式
  3. int staff_size = 27;                // staff_size不是常量表达式
  4. const int sz = get_size();      // sz不是常量表达式

尽管staff_size的初始值是个字面值常量,但由于它的数据类型只是一个普通int而非const int,所以它不属于常量表达式。另一方面,尽管sz本身是一个常量,但它的具体值直到运行时才能获取到,所以也不是常量表达式。

constexpr变量

在一个复杂系统中,很难(几乎肯定不能)分辨一个初始值到底是不是常量表达式。当然可以定义一个const变量并把它的初始值设为我们认为的某个常量表达式,但在实际使用时,尽管要求如此却常常发现初始值并非常量表达式的情况。可以这么说,在此种情况下,对象的定义和使用根本就是两回事儿。

C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化:

  1. constexpr int mf = 20;          // 20是常量表达式
  2. constexpr int limit = mf + 1;   // mf + 1是常量表达式
  3. constexpr int sz = size();      // 只有当size是一个constexpr函数时, 才是一条正确的声明语句

尽管不能使用普通函数作为constexpr变量的初始值,但是正如6.5.2节(第239页)将要介绍的,新标准允许定义一种特殊的constexpr函数。这种函数应该足够简单以使得编译时就可以计算其结果,这样就能用constexpr函数去初始化constexpr变量了。

一般来说,如果你认定变量是一个常量表达式,那就把它声明成constexpr类型。

字面值类型

常量表达式的值需要在编译时就得到计算,因此对声明constexpr时用到的类型必须有所限制。因为这些类型一般比较简单,值也显而易见、容易得到,就把它们称为"字面值类型"(literal type)。

到目前为止接触过的数据类型中,算术类型、引用和指针都属于字面值类型。自定义类Sales_item、IO库、string类型则不属于字面值类型,也就不能被定义成constexpr。其他一些字面值类型将在7.5.6节(第299页)和19.3节(第832页)介绍。

尽管指针和引用都能定义成constexpr,但它们的初始值却受到严格限制。一个constexpr指针的初始值必须是nullptr或者0,或者是存储于某个固定地址中的对象。

6.1.1节(第204页)将要提到,函数体内定义的变量一般来说并非存放在固定地址中,因此constexpr指针不能指向这样的变量。相反的,定义于所有函数体之外的对象其地址固定不变,能用来初始化constexpr指针。同样是在6.1.1节(第204页)中还将提到,允许函数定义一类有效范围超出函数本身的变量,这类变量和定义在函数体之外的变量一样也有固定地址。因此,constexpr引用能绑定到这样的变量上,constexpr指针也能指向这样的变量。

指针和constexpr

必须明确一点,在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指的对象无关:

  1. const int *p = nullptr;         // p是一个指向整型常量的指针
  2. constexpr int *q = nullptr;     // q是一个指向整数的常量指针

p和q的类型相差甚远,p是一个指向常量的指针,而q是一个常量指针,其中的关键在于constexpr把它所定义的对象置为了顶层const(参见2.4.3节,第63页)。

与其他常量指针类似,constexpr指针既可以指向常量也可以指向一个非常量:

    1. constexpr int *np = nullptr;    // np是一个指向整数的常量指针,其值为空
    2. int j = 0;
    3. constexpr int i = 42;       // i的类型是整型常量
    4. // i和j都必须定义在函数体之外
    5. constexpr const int *p = &i;    // p 是常量指针,指向整型常量i
    6. constexpr int *p1 = &j;         // p1是常量指针,指向整数j

constexpr-C++11的更多相关文章

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

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

  2. C++11 in Qt5

    本文转载自:http://woboq.com/blog/cpp11-in-qt5.html   C++11 in Qt5 Posted by Olivier Goffart on 11 June 20 ...

  3. c++ primer读书笔记之c++11(二)

    1 新的STL模板类型,std::initializer_list<T> c++11添加了initializer_list模板类型,用于提供参数是同类型情况的可变长度的参数传递机制,头文件 ...

  4. Qt5 中对 C++11 一些新特性的封装

    在 Qt5 中,提供更多 C++11 的特性支持,接下来我们将进行详细的说明. slots (槽) 的 Lambda 表达式 Lambda表达式 是 C++11 中的一个新语法,允许定义匿名函数.匿名 ...

  5. 【Qt开发】Qt5 中对 C++11 一些新特性的封装

    C++11 是现在的 C++ 标准的名称,C++11 为 C++ 语言带来很多新特性. 而 Qt 4.8 是 Qt 首个在其 API 中开始使用一些新的 C++11 特性的版本,我之前写过一篇博文:C ...

  6. C++ Standard Library

    C++ Standard Library *注:内容主要是对參考1的学习记录.知识点与图片大都来源于该书, 部分知识点与图片来源于參考2. 详细參考信息,见最下方參考. * C++98中新支持的语言特 ...

  7. C++ 语言程序设计(清华大学)1

    1.回文数字判断方法(逆过来数值相等):y=y*10+x%10; x /= 10; return(x==y) 2.int rand(void)函数,所需头文件<cstdlib> ,功能是求 ...

  8. [C++]变量声明与定义的规则

    声明与定义分离 Tips:变量能且仅能被定义一次,但是可以被多次声明. 为了支持分离式编译,C++将定义和声明区分开.其中声明规定了变量的类型和名字,定义除此功能外还会申请存储空间并可能为变量赋一个初 ...

  9. 地区sql

    /*Navicat MySQL Data Transfer Source Server : localhostSource Server Version : 50136Source Host : lo ...

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

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

随机推荐

  1. Windows下删除顽固文件夹

    参考链接: https://www.cnblogs.com/azbane/p/9808802.html 第一步:修改当前文件夹所有者为管理员 takeown /f * /a /r 第二步:修改管理员权 ...

  2. vue函数式组件详解

    本篇将详细介绍vue组件化之函数式组件,会用到以下api: Vue.component().Vue.extend().$createElement.patch(). 从事vue开发的小伙伴,平时组件化 ...

  3. LAMP和LNMP环境搭建的艰辛历程

    目录 1. LAMP环境的搭建 1. Apache 安装apache遇到的问题 2. mysql 登录mysql的方法 3. PHP 2. Lnmp环境的搭建 1. nginx 2. PHP 3. 配 ...

  4. docker报错Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

    docker报错Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon run ...

  5. js中判断数据类型的四种方法总结

    js中判断数据类型的四种方法 前言 在js中,我们经常需要判断数据的类型,那么哪些方法可以用来判断数据的类型呢?哪种方法判断数据类型最准确呢? 我们来一个个分析: 1.typeof typeof是一个 ...

  6. ant的copy标签使用方法

    对于ant里拷贝用的标签的用法,此文(来自 http://electiger.blog.51cto.com/112940/39575 )讲得很好,注意其中黑体字部分,今天被这个问题耽误了20分钟. A ...

  7. 脚本小子学习--vulnhub靶机DC8

    @ 目录 前言 一.环境搭建 二.目标和思路 三.实际操作 1.信息收集 2.getshell 总结 前言 通过一些靶机实战练习,学习使用现有的工具来成为脚本小子. 一.环境搭建 靶机:Linux虚拟 ...

  8. 微信SDK的使用

    一.导入依赖 <!--微信支付--> <dependency> <groupId>com.github.wxpay</groupId> <arti ...

  9. 【原创】利用“进程注入”实现无文件不死webshell

    引子 上周末,一个好兄弟找我说一个很重要的目标shell丢了,这个shell之前是通过一个S2代码执行的漏洞拿到的,现在漏洞还在,不过web目录全部不可写,问我有没有办法搞个webshell继续做内网 ...

  10. Linux文件系统只读 解决方案:

    Linux系统Read-only file system,文件系统只读排查解决方案:文件系统只读机制:当文件系统自身的校验机制发现文件系统存在问题时,为避免文件系统受到进一步的损坏,系统会把文件系统设 ...