7.1.5的constexpr
指示符[dcl.constexpr]表示:
constexpr
构造函数的定义应满足以下要求:
- 类不得有任何虚基类;
- 对于默认复制/移动构造函数,其类不得有一个可变的子对象,该子对象是一个变体成员;
- 每个参数类型都必须是字面类型;
- 其函数体不得是函数尝试块;
此外,它的函数体应为= delete,或者它应满足以下要求:
- 其函数体应为= default,或其函数体的复合语句应符合constexpr函数的函数体要求;
- 每个非变体非静态数据成员和基类子对象都应初始化(12.6.2);
- 如果类是具有变体成员(9.5)的联合体,则其中一个成员必须初始化;
- 如果类是类似于联合体但不是联合体的类,则对于其中具有变体成员的每个匿名联合成员,都必须初始化其中的一个;
- 对于非委托构造函数,用于初始化非静态数据成员和基类子对象的每个所选构造函数都应是constexpr构造函数;
- 对于委托构造函数,目标构造函数应为constexpr构造函数。
简而言之,只要满足上述其他要求,= default
就是constexpr
默认构造函数的有效定义。
那么这如何与未初始化的构造有关呢?
没有关系。
例如:
constexpr seconds x1{};
以上内容能够正常工作且将x1
初始化为0s
。然而:
constexpr seconds x2;
error: default initialization of an object of const type 'const seconds'
(aka 'const duration<long long>') without a user-provided default
constructor
constexpr seconds x2;
^
{}
1 error generated.
因此,要创建一个constexpr
默认构造的duration
,您必须对其进行零初始化。而= default
实现允许使用{}
进行零初始化。
完整的工作演示:
template <class Rep>
class my_duration
{
Rep rep_;
public:
constexpr my_duration() = default;
};
int
main()
{
constexpr my_duration<int> x{};
}
有趣的侧边栏
在回答中我学到了一些东西,想和大家分享:
我一直在想为什么以下内容不起作用:
using Rep = int;
class my_duration
{
Rep rep_;
public:
constexpr my_duration() = default;
};
int
main()
{
constexpr my_duration x{};
}
error: defaulted definition of default constructor is not constexpr
constexpr my_duration() = default;
^
为什么将这个类改成非模板类会破坏
constexpr
默认构造函数?! (
更新:在C++20中现在可以编译通过)。然后我尝试了这个:
using Rep = int;
class my_duration
{
Rep rep_;
public:
my_duration() = default;
};
int
main()
{
constexpr my_duration x{};
}
编译器再次喜欢它。
CWG可能还没有关于此的问题,这个行为似乎有点不一致。这可能只是因为我们(整个行业)仍在学习constexpr
。C++20中已修复。
constexpr
,因此即使默认版本不满足constexpr
构造函数的要求,它仍然可以使用 - 只是不能用于常量表达式。 - T.C.duration::rep
是一种类型,而不是成员,对吧? - AndyGduration::rep
但名称未指定的成员变量。 - Brad Spencer