C++11类型说明符:constexpr

关键字constexpr用于修饰常量表达式(const express),具体说明如下


字面值常量(literal)

  • 由形式和值来决定数据类型
  • 可手动指定类型
    如:
    • 常规
      20 —— 十进制数
      0x8 —— 十六进制数
      “hello” —— char[6]
    • 指定类型
      3F —— float
      L’a’ —— whar_t
      u8”hi!” —— utf-8
      3.14159 —— long double

常量表达式(const express)

The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time. Such variables and functions can then be used where only compile time constant expressions are allowed (provided that appropriate function arguments are given). A constexpr specifier used in an object declaration implies const. A constexpr specifier used in a function or static member variable (since C++17) declaration implies inline.

其中literal就是const express的一种。从文档可知,const express主要性质是可以在编译期间得到值。同时,constexpr修饰的对象自动获得常量属性,constexpr修饰的函数自动获得内联属性。


constexpr变量

满足以下条件:

  • 其值必须为literal类型。
  • 必须能立即初始化,意味着所有的初始化方法,包括所有隐式转换、调用构造函数等,都必须为const express

特别需要说明的是指针变量,constexpr类型的指针变量有以下的几种存在方式:

  • 指向nullptr

    1
    constexpr int *p = nullptr;
  • 指向全局变量、static变量,因其地址不会改变

    1
    2
    int i = 0; // i 定义在函数外部,是一个全局变量
    constexpr int *p = &i; // 正确
  • 另外:
    虽然constexprconst在某些方面有点相似,但constexpr int *q = nullptr;的含义却与const int *q = nullptr;的有些出入,前者q不能修改,后者*q不能修改。若需要指向常量的常量指针,可以这样定义:constexpr const int *q = nullptr;,这样q*q就都是不可修改的常量了。


constexpr函数

constexpr函数会被隐式地inline
满足以下条件:

  • 形参和返回值都得为literal类型
  • 只能有一条return语句

例:

1
2
3
4
5
constexpr int new_sz() {return 42;}
cosntexpr size_t scale(size_t cnt) {return new_sz() * cnt;}
int arr[scale(2)]; // 正确,scale(2)是const express
int n = 2;
int arr2[scale(n)]; // 错误,scale(n)不是const express


constexpr类

满足以下条件:

  • 该类是聚合类,所谓聚合类:
    • 所有成员都是public
    • 无显式定义的构造函数
    • 成员无初始值
    • 无基类,无virtual函数
  • 若不是聚合类,需要满足
    • 数据成员必须都为literal类型(函数成员无须是)
    • 至少含有一个constexpr构造函数
    • 只能使用默认的析构函数

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
class Debug
{
public:
constexpr Debug(bool b = true) : hw(b), io(b), other(b) {}
constexpr Debug(bool h, bool i, bool o) : hw(h), io(i), other(o) {}
constexpr bool any() { return hw || io || other; }
void set_io(bool b) { io = b; }
void set_hw(bool b) { hw = b; }
void set_other(bool b) { other = b; }
private:
bool hw;
bool io;
bool other;
};
int main()
{
constexpr Debug io_sub(false, true, false);
if (io_sub.any())
std::cerr << "print appropriate error messages" << std::endl;
return 0;
}