002 constexpr

作者: 赵者也 | 来源:发表于2020-01-19 14:03 被阅读0次

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

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

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

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

函数体内定义的变量一般来说并非存放在固定地址中,因此 constexpr 指针不能指向这样的变量。相反地,定义于所有函数体之外的对象其地址固定不变,能用来初始化 constexpr 指针。

constexpr 函数

constexpr 函数是指能用于常量表达式的函数。定义 constexpr 函数的方法与其他函数类似,不过要遵循几项约定:函数的返回类型及所有形参的类型都得是字面值类型,而且函数体中必须有且只有一条 return 语句:

constexpr int new_sz() { return 42;}
constexpr int fsz = new_sz();

我们把 new_sz 定义成无参数的 constexpr 函数。因为编译器能在程序编译时验证 new_sz 函数返回的是常量表达式,所以可以用 new_sz 函数初始化 constexpr 类型的变量 fsz。

执行该初始化任务时,编译器把对 constexpr 函数的调用替换成其结果值。为了能在编译过程中随时展开,constexpr 函数被隐式地指定为内联函数。

constexpr 函数体内也可以包含其他语句,只要这些语句在运行时不执行任何操作就行。例如,constexpr 函数中可以有空语句、类型别名以及 using 声明。

我们允许 constexpr 函数的返回值并非一个常量:

constexpr int new_sz() { return 42;}
// 如果 cnt 是常量表达式,则 scale(cnt) 也是常量表达式
constexpr size_t scale(size_t cnt) { return new_sz()*cnt; }
int arr[scale(2)];  // 正确:scale(2) 是常量表达式
int i = 2;          // i 不是常量表达式
int a2[scale(i)];   // 错误:scale(i) 不是常量表达式

当把 scale 函数用在需要常量表达式的代码块中时,由编译器负责检查函数的结果是否符合要求。如果结果恰好不是常量表达式,编译器将发出错误信息。

所以说,constexpr 函数不一定返回常量表达式。

constexpr 构造函数

尽管构造函数不能是 const 的,但是字面值常量类的构造函数可以是 constexpr 函数。事实上,一个字面值常量类必须至少提供一个 constexpr 构造函数。

constexpr 构造函数可以声明成 = default 的形式(或是删除函数的形式)。否则,constexpr 构造函数就必须既符合构造函数的要求,又符合 constexpr 构造的要求(意味着它能拥有的唯一可执行语句就是返回语句)。综合这两点可知,constexpr 构造函数体一般来说应该是空的。我们通过前置关键字 constexpr 就可以声明一个 constexpr 构造函数了:

  class Debug {
    public:
        constexpr Debug(bool b = true) : hardwareError(b), ioError(b), otherError(b) {}
        constexpr Debug(bool hw, bool io, bool ot) : hardwareError(hw), ioError(io), otherError(ot) {}
        constexpr bool error() { return  hardwareError || ioError || otherError;}
        void setIOError(bool is) { ioError = is; }
        void setHardwareError(bool is) { hardwareError = is; }
        void setOtherError(bool is) { otherError = is; }

    private:
        bool hardwareError;
        bool ioError;
        bool otherError;
  };

constexpr 构造函数必须初始化所有数据成员,初始化或者使用 constexpr 构造函数,或者是一条常量表达式。

constexpr 构造函数用于生成 constexpr 对象以及 constexpr 函数的参数或返回类型:

    constexpr Debug io_sub(false, true, false);
    if (io_sub.error()) {
        std::cerr << "There are some error messages ..." << std::endl;
    }
    constexpr Debug prod(false);
    if (prod.error()) { // 等价于 if (false)
        std::cerr << "There is no error messages ..." << std::endl;
    }

相关文章

  • 002 constexpr

    C++ 11 新标准规定,允许将变量声明为 constexpr 类型以便由编译器来验证变量的值是否是一个常量表达式...

  • constexpr:编译期与运行期之间的神秘关键词

    参考大神博客,整理constexpr的用法和注意事项 一、概念,constexpr objects C++ pri...

  • constexpr

    常量表达式是指值不会改变并且在编译过程就能是到计算结果的表达式。一个对象是不是常量表达式由它的数据类型和初始值共同...

  • C++ constexpr

    c++ constexpr构造函数有什么作用 给构筑bai函数加上constexpr之后, 这个构筑函数就只能du...

  • cpp constexpr

    cpp 的运行时容器,函数库有stl, constexpr库可以考虑 Sprout ,https://github...

  • C++11/14/17

    关键字:auto, nullptr, explicit, final, override, constexpr,...

  • C++11/14 constexpr 用法

    constexpr是C++11开始提出的关键字,其意义与14版本有一些区别。C++11中的constexpr指定的...

  • 顺序表的基本操作

    #include"SqList.h" #include"pch.h" #include constexpr aut...

  • C++14

    Lambda 函数constexpr类型推导二进制常量变量模板

  • 2018-05-06

    auto 模板别名 收缩转换 constexpr inline lambda表达式 初级 高级 函...

网友评论

    本文标题:002 constexpr

    本文链接:https://www.haomeiwen.com/subject/jbbvdqtx.html