在 C++03 中,该对象具有动态初始化
struct Data {
int i;
int j;
};
Data init_data(); // calculate something
const Data data = init_data();
即程序启动时,在main运行之前,会调用函数并初始化对象。
在 C++11 中,对象可以有常量初始化,一种静态初始化的形式,意味着它的值是在编译时设置的,并且在程序开始。这对于避免 static initialization order fiasco 等非常有用。为确保类型得到常量初始化,它必须由常量表达式初始化,因此必须有一个constexpr 构造函数,并且在完整表达式中调用的任何函数都必须是constexpr 函数。
Data 类型是微不足道的,所以它隐式声明的构造函数是 constexpr 构造函数,所以要使全局 data 经历常量初始化,我们只需要将 init_data() 设为constexpr函数:
struct Data {
int i;
int j;
};
constexpr Data init_data(); // calculate something
constexpr Data data = init_data();
文字类型的优点是此类类型可用于其他常量表达式,即需要编译时常量的上下文中。所以现在我们将data 对象作为编译时常量,我们可以在其他常量表达式中使用它,例如初始化其他编译时常量:
const int i = ::data.i;
我们可以将Data 类型用于具有类内初始化程序的静态数据成员:
struct MoreData {
static constexpr Data zerozero = Data{}; // OK, Data is a literal type
};
如果Data 不是文字类型,我们将不得不写:
struct MoreData {
static const Data zerozero;
};
// in moredata.cc
const Data MoreData::zerozero = Data{};
然后只看到标头的代码不知道MoreData::zerozero 的值,并且不能在编译时优化中使用它。
所以“文字类型”规则的优点是它们允许您定义可以在常量表达式中使用的新类类型。在 C++03 中,只有极少数类型(例如整数)可用于常量表达式,例如整数文字,例如 1 或 0x23 或整数类型的编译时常量。在 C++11 中,您可以编写自己的类型,这些类型在其构造函数中可以具有中等复杂的逻辑(可以在 constexpr 函数中表达的任何内容),但仍可用作编译时常量。
另外我想知道一个集合成员函数是否需要是 constexpr,即
constexpr 成员函数是const 成员函数的特例,因此它不能修改该类型的(非-mutable)成员。修改对象的setter函数不能是const。
要成为文字类型,类必须遵循一些规则,包括至少有一个 constexpr 构造函数。这并不意味着该类型的所有对象必须是constexpr常量,它只是意味着该类型的对象可以是constexpr常量,如果它们被声明为这样并使用类的constexpr 构造函数之一进行初始化。再次使用Data 示例,程序中的大多数对象都不是常量:
Data d = { 0, 1 };
d.i = d.i + 5;
因此,如果您添加了一个 setter,一个修改对象的函数,那么只有在该类型的非常量对象上使用它才有意义,并且像任何其他修改类型的函数一样,它不应该是