std::chrono::duration
的默认构造函数定义如下:
constexpr duration() = default;
(例如,请参阅cppreference.com或libstdc ++源代码。)
然而,cppreference.com also says this关于constexpr
构造函数:
constexpr构造函数必须满足以下要求:
...
每个基类和每个非静态成员都必须初始化,在构造函数初始化列表中或由成员大括号或相等的初始化程序。另外,所涉及的每个构造函数都必须是constexpr构造函数,并且每个大括号或相等的初始化程序的每个子句都必须是一个常量表达式
如果我对默认构造函数感到困惑,那么使用= default
生成的默认构造函数的cppreference.com seems to say与隐式构造函数的定义不同。
然而,(大多数)持续时间的rep
类型是一个裸整数类型。因此,= default
的显式duration
默认构造函数不应等同于
constexpr duration() {}
当然会保留类型为duration::rep
的整数成员变量未初始化?事实上,duration
的标准行为不是默认构造的值 未初始化的吗? (但我找不到明确说明这一点的参考文献。)
那么如果= default
的{{1}}构造函数保留未初始化的非静态成员变量,它怎么能成为duration
?我错过了什么?
答案 0 :(得分:12)
7.1.5 constexpr
说明符[dcl.constexpr]说:
constexpr
构造函数的定义应满足。{1}} 以下要求:
- 该课程不得有任何虚拟基类;
- 对于默认的复制/移动构造函数,该类不应具有作为变体成员的可变子对象;
- 每个参数类型都应为文字类型;
- 它的函数体不应该是函数 - try-block;
此外,其功能体应为=删除,或者应该是 满足以下要求:
- 其函数体应为= 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
默认构造函数?!
然后我尝试了这个:
using Rep = int;
class my_duration
{
Rep rep_;
public:
my_duration() = default; // removed constexpr
};
int
main()
{
constexpr my_duration x{};
}
编译器再次喜欢它。
如果还没有CWG问题,可能应该有。这种行为似乎有些不一致。这可能只是因为我们(整个行业)仍然在学习constexpr
。