Constexpr 构造函数 (C++11)

使用 constexpr 说明符声明的构造函数是 constexpr 构造函数。 以前,只有内置类型的表达式可以是有效的常量表达式。 通过 constexpr 构造函数,可以将用户定义类型的对象包括在有效常量表达式中。

constexpr 构造函数的定义必须满足以下需求:
  • 包含类不得具有任何虚拟基类。
  • 每个参数类型都是文字类型。
  • 其函数体为 = delete= default; 否则,它必须满足以下约束:
    • 它不是函数 try 块。
    • 其中的复合语句必须仅包含以下语句:
      • null 语句
      • static_assert 声明
      • 未定义类或枚举的 typedef 声明
      • using 伪指令
      • using 声明
  • 初始化每个 非静态数据成员 和基类子对象。
  • 用于初始化非静态数据成员和基类子对象的每个构造函数都是 constexpr 构造函数。
  • 未由成员初始化程序标识命名的所有非静态数据成员的初始化程序都是常量表达式。
  • 初始化数据成员时,以下上下文中涉及的所有隐式转换都必须在常量表达式中有效:
    • 调用任何构造函数
    • 将任何表达式转换为数据成员类型

隐式定义的缺省构造函数执行将由用户编写的缺省构造函数为该类执行的类初始化集,该类没有初始化程序和空的复合语句。 如果该用户定义的缺省构造函数将满足 constexpr 构造函数的需求,那么隐式定义的缺省构造函数是 constexpr 构造函数。

constexpr 构造函数隐式内联。

以下示例演示了 constexpr 构造函数的用法:
struct BASE {
};

struct B2 {
  int i;
};

//NL is a non-literal type.
struct NL {     
  virtual ~NL() {   
  }
};    

int i = 11;

struct D1 : public BASE {
  //OK, the implicit default constructor of BASE is a constexpr constructor.
  constexpr D1() : BASE(), mem(55) { }
  
  //OK, the implicit copy constructor of BASE is a constexpr constructor.
  constexpr D1(const D1& d) : BASE(d), mem(55) { } 

  //OK, all reference types are literal types.
  constexpr D1(NL &n) : BASE(), mem(55) { }

  //The conversion operator is not constexpr.
  operator int() const { return 55; }      

private:    
  int mem;
};  

struct D2 : virtual BASE { 
  //error, D2 must not have virtual base class.
  constexpr D2() : BASE(), mem(55) { }    

private:
  int mem; 
};  

struct D3 : B2 {
  //error, D3 must not be a function try block.   
  constexpr D3(int) try : B2(), mem(55) { } catch(int) { }

  //error, illegal statement is in body.
  constexpr D3(char) : B2(), mem(55) { mem = 55; } 
  
  //error, initializer for mem is not a constant expression. 
  constexpr D3(double) : B2(), mem(i) { }

  //error, implicit conversion is not constexpr. 
  constexpr D3(const D1 &d) : B2(), mem(d) { }                   

  //error, parameter NL is a non-literal type.
  constexpr D3(NL) : B2(), mem(55) { } 

private: 
  int mem;
};