P1008(“禁止与用户声明的构造函数聚合”)在实践中何时有用?

Posted

技术标签:

【中文标题】P1008(“禁止与用户声明的构造函数聚合”)在实践中何时有用?【英文标题】:When is P1008 ("prohibit aggregates with user-declared constructors") useful in practice? 【发布时间】:2020-03-09 11:13:06 【问题描述】:

P1008 ("Prohibit aggregates with user-declared constructors") 已成为 C++20 标准的一部分,以防止在使用聚合初始化时出现意外行为:

struct X 
  int i42;
  X() = delete;
;

int main() 
  X x23; // Compiles in C++17, error in C++20

我同意上面的X x23; 语句不应该编译。然而,我遇到的所有证明 P1008 的例子根本不现实——它们纯粹是句法,基本上没有意义foo/bar/bazcode sn-ps。

P1008在实践中解决了什么问题?我很难想象我最终会如何在一个真实的程序中写出类似上述X 的东西。

删除 C++17 聚合中的默认构造函数不提供其他构造函数来初始化它对我来说似乎不现实。

【问题讨论】:

我觉得这艘船已经为这个特殊的问题航行了。对于它的价值,当我第一次遇到这种情况时,我有点惊讶,导致this question(虽然现在我不记得原来的例子了),但是就像......是的。 @Barry:我不想写反提案。我只是对受 P1008 影响的真实案例感到好奇……如果有的话 @Barry:即使你的例子也没有说服力。为什么会有一个带有 =default 私有构造函数和所有公共数据成员的类? @VittorioRomeo:因为任何能够获取类型的人都应该能够访问变量。它正在为private 访问类之外禁止的类型创建新值。如果您有权访问现有值,您仍然可以正常处理它。 【参考方案1】:

最明显的情况是这样的:

struct X

private:
    X() = default;
;

X x;

这不是应该能够在私有可访问上下文之外初始化的类型。但它可以。

现在,这些类型可能看起来很傻,但它们实际上对于实现通过转发函数工作的私有函数很有用。例如make_shared 不能调用声明为private 的构造函数,即使您将make_shared 模板设为朋友也是如此。因此,您创建构造函数public,但要求用户传递一个类型的实例,该实例只能由具有private 访问权限的人构造。所以X 要么是目标类的成员类型,要么X 将使目标类成为friend

【讨论】:

假设我理解正确,您指的是“密码习语”。老实说,对于 P1008 的影响,这似乎不是很激励,但至少它有点现实。 @VittorioRomeo:到底有什么影响?在我看来,它破坏的任何代码都是不遵循 0 规则的代码,因此可能应该被破坏。 “零规则”究竟是“不指定任何特殊成员函数”还是还包括“将所有特殊成员函数指定为=default”是有争议的。在我的心智模型中,这些是等价的。这是一个影响示例:twitter.com/tcanens/status/1185379657350352897 @VittorioRomeo:array 的析构函数不应该是无条件的noexcept。对我来说,这似乎是为什么这是一件好事的一个例子。如果一个类型足够关心子对象在做什么,它想要强制执行noexcept 破坏,那么我会说它不是一个逻辑聚合。聚合对象在功能上应该与将聚合的内容声明为同一范围内的变量相同。 包括 noexcept 这些类型的析构函数。这是我想要的功能。 这种类型是微不足道的,所以如果你能命名它,你就可以祝福一个对象存在,不管是否是私有构造函数。如果您将名称设为私有,那么 ctor 的私有性就不是很重要。

以上是关于P1008(“禁止与用户声明的构造函数聚合”)在实践中何时有用?的主要内容,如果未能解决你的问题,请参考以下文章

P1008 三连击

P1008三连击

P1008 三连击

bzoj P1008

luogu P1008 三连击

AC日记——三连击 洛谷 P1008