C++17 中的显式默认构造函数
Explicit default constructors in C++17
在 C++17 中,标准库中的空标记类型现在具有标记为 explicit
和 = default
的默认构造函数。例如,std::piecewise_construct_t
现在定义为
struct piecewise_construct_t { explicit piecewise_construct_t() = default; };
我的问题很简单,从 C++14 开始发生这种变化的原因是什么?显式默认的显式默认构造函数 (!) 对空 class 意味着什么?
(为了避免被标记为欺骗:this question from 2010 asks about the purpose of explicit default constructors, but that was pre-C++11 and a long time ago now so things have likely changed. 是最近的,但答案似乎表明无论是否存在默认构造函数,都会执行聚合初始化,所以我很好奇了解最新标准中此更改的原因。)
库更改的基本原理在 LWG 2510 "Tag types should not be DefaultConstructible
":
std::experimental::optional
, for certain reasons, specifies its nullopt
type to not be DefaultConstructible
. It doesn't do so for its tag type in_place_t
and neither does the standard proper for any of its tag types. That turns out to be very unfortunate, consider the following:
#include <memory>
#include <array>
void f(std::array<int, 1>, int) {} // #1
void f(std::allocator_arg_t, int) {} // #2
int main()
{
f({}, 666); // #3
}
The call at #3 is ambiguous. What's even worse is that if the overload #1 is removed, the call works just fine. The whole point of a tag type is that it either needs to mentioned in a call or it needs to be a forwarded argument, so being able to construct a tag type like that makes no sense.
LWG 问题与 CWG 1518 "Explicit default constructors and copy-list-initialization" 并行发展,后者具有有用的背景。
在 C++17 中,标准库中的空标记类型现在具有标记为 explicit
和 = default
的默认构造函数。例如,std::piecewise_construct_t
现在定义为
struct piecewise_construct_t { explicit piecewise_construct_t() = default; };
我的问题很简单,从 C++14 开始发生这种变化的原因是什么?显式默认的显式默认构造函数 (!) 对空 class 意味着什么?
(为了避免被标记为欺骗:this question from 2010 asks about the purpose of explicit default constructors, but that was pre-C++11 and a long time ago now so things have likely changed.
库更改的基本原理在 LWG 2510 "Tag types should not be DefaultConstructible
":
std::experimental::optional
, for certain reasons, specifies itsnullopt
type to not beDefaultConstructible
. It doesn't do so for its tag typein_place_t
and neither does the standard proper for any of its tag types. That turns out to be very unfortunate, consider the following:#include <memory> #include <array> void f(std::array<int, 1>, int) {} // #1 void f(std::allocator_arg_t, int) {} // #2 int main() { f({}, 666); // #3 }
The call at #3 is ambiguous. What's even worse is that if the overload #1 is removed, the call works just fine. The whole point of a tag type is that it either needs to mentioned in a call or it needs to be a forwarded argument, so being able to construct a tag type like that makes no sense.
LWG 问题与 CWG 1518 "Explicit default constructors and copy-list-initialization" 并行发展,后者具有有用的背景。