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 中的显式构造函数?

多参数构造函数上的显式关键字?

为啥我的显式构造函数会为我的转换运算符创建这种歧义?

真的没有来自 std::string_view 的 std::string 的显式构造函数吗?

显式默认构造函数的目的

运算符重载中的显式构造?