C++17 中的显式默认构造函数
Posted
技术标签:
【中文标题】C++17 中的显式默认构造函数【英文标题】:Explicit default constructors in C++17 【发布时间】:2017-10-25 11:51:35 【问题描述】:在 C++17 中,标准库中的空标记类型现在具有标记为 explicit
和 = default
的默认构造函数。例如,std::piecewise_construct_t
现在定义为
struct piecewise_construct_t explicit piecewise_construct_t() = default; ;
我的问题很简单,从 C++14 发生这种变化的原因是什么?显式默认的显式默认构造函数 (!) 对空类意味着什么?
(为了避免被标记为骗子:this question 从 2010 年开始询问显式默认构造函数的目的,但那是 C++11 之前和很久以前的事,所以事情可能已经改变了。This question是较新的,但答案似乎表明无论是否存在默认构造函数都会执行聚合初始化,所以我很好奇最新标准中这种变化的原因。)
【问题讨论】:
【参考方案1】:库更改的理由在LWG 2510 "Tag types should not be DefaultConstructible
":
std::experimental::optional
,出于某些原因,将其nullopt
类型指定为不是DefaultConstructible
。它的标签类型in_place_t
不这样做,标准也不适用于它的任何标签类型。事实证明这是非常不幸的,请考虑以下几点:#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
#3 的调用不明确。更糟糕的是,如果重载 #1 被移除,调用就可以正常工作。标记类型的全部意义在于,它要么需要在调用中提及,要么需要作为转发参数,因此能够构造这样的标记类型是没有意义的。
LWG 问题与具有有用背景的CWG 1518 "Explicit default constructors and copy-list-initialization" 并肩发展。
【讨论】:
嗯,你知道 LWG 是否打算让#3 保持模棱两可吗?因为在allocator_arg_t
上有一个显式的默认构造函数并不会改变这一点。它只会改变“更糟糕的”部分。
@T.C.怎么模棱两可?具有显式构造函数的类型不是聚合,如果它选择显式构造函数,则复制列表初始化是格式错误的。 (不,FWIW,我不知道 LWG 对 2510 的意图。那是在我之前。)
啊,我错过了[dcl.init.list]/3.4:“否则,如果初始化列表没有元素并且T
是具有默认构造函数的类类型,则对象为值-初始化。”真不幸。
复制列表初始化如果选择显式构造函数则格式错误,但该规则不会影响隐式转换序列的形成(这是控制重载解决方案可行性的原因)。相关的子条款是 [over.ics.list]。
但也许他们知道这一点,因为他们将 2510 措辞与我的 nullopt_t
措辞 (2736) 同时移动,明确表示“没有默认构造函数”。 /耸肩以上是关于C++17 中的显式默认构造函数的主要内容,如果未能解决你的问题,请参考以下文章
operator== 和 boost::detail::atomic_count 中的显式构造函数?