[英]How can std::chrono::duration::duration() be constexpr?
The default constructor of std::chrono::duration
is defined as follows: std::chrono::duration
的默认构造函数定义如下:
constexpr duration() = default;
(For example, see cppreference.com or the libstdc++ source.) (例如,请参阅cppreference.com或libstdc ++源代码。)
However, cppreference.com also says this about constexpr
constructors: 但是, cppreference.com也说过
constexpr
构造函数:
A constexpr constructor must satisfy the following requirements:
constexpr构造函数必须满足以下要求:
...
...
every base class and every non-static member must be initialized , either in the constructors initialization list or by a member brace-or-equal initializer.
必须在构造函数初始化列表中或通过成员大括号或相等的初始化程序初始化每个基类和每个非静态成员 。 In addition, every constructor involved must be a constexpr constructor and every clause of every brace-or-equal initializer must be a constant expression
另外,所涉及的每个构造函数都必须是constexpr构造函数,并且每个大括号或者相等的初始化程序的每个子句都必须是一个常量表达式
And in case I was confused about default constructors, cppreference.com seems to say that default constructors brought into being with = default
aren't defined differently than implicit default constructors. 如果我对默认构造函数感到困惑, cppreference.com似乎会说默认构造函数与
= default
一起使用的定义与隐式构造函数的定义不同。
Yet, the rep
type for (most) durations is a bare integer type. 然而,(大多数)持续时间的
rep
类型是裸整数类型。 So, shouldn't the explicit = default
default constructor for duration
be equivalent to 因此,
duration
的explicit = default
默认构造函数不应该等效于
constexpr duration() {}
which of course would leave the integer member variable of type duration::rep
uninitialized? 当然会留下
duration::rep
uninitialized类型的整数成员变量? And, in fact, isn't the standard behaviour of duration
such that default-constructed values are uninitialized? 而且,事实上,不是标准行为
duration
,使得默认构造值初始化? (But I can't find a reference that explicitly says this.) (但我找不到明确说明这一点的参考文献。)
So how can the = default
constructor for duration
be constexpr
if it leaves a non-static member variable uninitialized? 那么如果
= default
非静态成员变量未初始化,那么= default
构造函数的duration
是constexpr
? What am I missing? 我错过了什么?
7.1.5 The constexpr
specifier [dcl.constexpr] says: 7.1.5
constexpr
说明符[dcl.constexpr]说:
The definition of a
constexpr
constructor shall satisfy the following requirements:constexpr
构造函数的定义应满足以下要求:
- the class shall not have any virtual base classes;
班级不得有任何虚拟基类;
- for a defaulted copy/move constructor, the class shall not have a mutable subobject that is a variant member;
对于默认的复制/移动构造函数,该类不应具有作为变体成员的可变子对象;
- each of the parameter types shall be a literal type;
每个参数类型应为文字类型;
- its function-body shall not be a function-try-block;
它的功能体不应该是功能试块;
In addition, either its function-body shall be = delete, or it shall satisfy the following requirements:
此外,其功能体应为=删除,或者它应满足以下要求:
- either its function-body shall be = default, or the compound-statement of its function-body shall satisfy the requirements for a function-body of a constexpr function;
其函数体应为= default,或其函数体的复合语句应满足constexpr函数的函数体的要求;
- every non-variant non-static data member and base class sub-object shall be initialized (12.6.2);
应初始化每个非变量非静态数据成员和基类子对象(12.6.2);
- if the class is a union having variant members (9.5), exactly one of them shall be initialized;
如果该类是具有变体成员的联合(9.5),则其中一个应该被初始化;
- if the class is a union-like class, but is not a union, for each of its anonymous union members having variant members, exactly one of them shall be initialized;
如果类是类似联合的类,但不是联合,对于每个具有变体成员的匿名联合成员,其中只有一个应该被初始化;
- for a non-delegating constructor, every constructor selected to initialize non-static data members and base class sub-objects shall be a constexpr constructor;
对于非委托构造函数,选择初始化非静态数据成员和基类子对象的每个构造函数都应该是constexpr构造函数;
- for a delegating constructor, the target constructor shall be a constexpr constructor.
对于委托构造函数,目标构造函数应该是constexpr构造函数。
In a nutshell, = default
is a valid definition of a constexpr
default constructor as long as the other requirements above are met. 简而言之,
= default
是constexpr
默认构造函数的有效定义,只要满足上述其他要求即可。
So how does this work with uninitialized constructions? 那么这如何与未初始化的结构一起工作呢?
It doesn't. 它没有。
For example: 例如:
constexpr seconds x1{};
The above works and initializes x1
to 0s
. 以上工作原理并将
x1
初始化为0s
。 However: 然而:
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.
So to create a constexpr
default constructed duration
, you must zero-initialize it. 因此,要创建
constexpr
默认构造duration
,必须对其进行零初始化 。 And the = default
implementation allows one to zero-initialize with the {}
. 并且
= default
实现允许使用{}
进行零初始化。
Complete working demo: 完整的工作演示:
template <class Rep>
class my_duration
{
Rep rep_;
public:
constexpr my_duration() = default;
};
int
main()
{
constexpr my_duration<int> x{};
}
Interesting Sidebar 有趣的侧边栏
I learned something in writing this answer, and wanted to share: 我在写这个答案时学到了一些东西,并希望分享:
I kept wondering why the following doesn't work: 我一直在想为什么以下不起作用:
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;
^
Why does making this class a non-template break the constexpr
default constructor?! 为什么让这个类成为非模板打破
constexpr
默认构造函数?!
Then I tried this: 然后我尝试了这个:
using Rep = int;
class my_duration
{
Rep rep_;
public:
my_duration() = default; // removed constexpr
};
int
main()
{
constexpr my_duration x{};
}
And the compilers like it again. 编译器再次喜欢它。
If there isn't already a CWG issue on this, there probably should be. 如果还没有CWG问题,可能应该有。 The behavior seems a bit inconsistent.
这种行为似乎有些不一致。 And this is probably just because we (the entire industry) are still learning about
constexpr
. 这可能只是因为我们(整个行业)仍在学习
constexpr
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.