在第一个示例中,d不是由常量表达式初始化,因为S::c不是
具有先前初始化的非易失性 const 对象,使用常量表达式初始化
(请参阅 C++11 [expr.const]p2,关于左值到右值转换的项目符号),因为 的初始化S::c不会先于d. 因此将使用静态初始化S::c(因为它是由常量表达式初始化的),但动态初始化可以用于d.
由于静态初始化先于动态初始化,d因此将50由其动态初始化器初始化。允许编译器将 的动态初始化转换d为静态初始化,但如果这样做,它必须生成d如果每个可以使用动态初始化的变量实际上都使用动态初始化时所具有的值。在这种情况下,d被初始化为50任一方式。有关这方面的更多信息,请参阅 C++11 [basic.start.init]p2。
没有办法添加constexpr到第一个示例来保证静态初始化用于d; 为此,您必须重新排序初始化。但是,添加constexpr将为第一个示例生成诊断信息,这至少可以让您确保不使用动态初始化(您得到静态初始化或编译错误)。
您可以更新第二种情况以确保使用静态初始化,如下所示:
struct S {
static const int c; // do not use constexpr here
};
constexpr int S::c = 5;
constexpr int d = 10 * S::c;
constexpr在不是定义的变量声明上使用它是不正确的,或者在不包含初始化程序的变量声明上使用它是不正确的,因此, constnotconstexpr必须在 的定义中使用struct S。此规则有一个例外,即在定义static constexpr文字、非整数类型的数据成员时,使用类中指定的初始化程序:
struct T { int n; };
struct U {
static constexpr T t = { 4 };
};
constexpr T U::t;
在这种情况下,constexpr必须在类的定义中使用,以便允许提供初始化程序,并且constexpr必须在静态数据成员的定义中使用,以便允许在常量表达式中使用。