为什么std :: swap在C ++ 20之前没有标记为constexpr?

问题描述 投票:4回答:2

在C ++ 20中,std::swap成为constexpr函数。

[我知道标准库在标记constexpr方面确实落后于该语言,但是到2017年,<algorithm>就像其他很多东西一样,已经成为constexpr了。但是-std::swap不是。我隐约记得有一些奇怪的语言缺陷阻止了这种标记,但是我忘记了细节。

有人可以简洁明了地解释吗?

动机:需要了解为什么在C ++ 11 / C ++ 14代码中标记类似std::swap()的函数constexpr可能不是一个好主意。

c++ c++11 constexpr c++20 std-swap
2个回答
8
投票

奇怪的语言是CWG 1581

第15条[special]非常清楚,特殊成员函数仅在使用过时才隐式定义。这为在未评估的上下文中的常量表达式带来了问题:

struct duration {
  constexpr duration() {}
  constexpr operator int() const { return 0; }
};

// duration d = duration(); // #1
int n = sizeof(short{duration(duration())});

这里的问题是我们不允许在此程序中隐式定义constexpr duration::duration(duration&&),因此初始化列表中的表达式不是常量表达式(因为它调用了尚未定义的constexpr函数),因此花括号初始化程序包含缩小的转换,因此该程序格式不正确。

如果取消注释第1行,则将隐式定义move构造函数,并且该程序有效。远距离的这种怪异的动作是非常不幸的。在这一点上,实现方式有所不同。

您可以阅读其余的问题描述。

[2017年,在Albuquerque的P0859中通过了此问题的解决方案(在C ++ 17发行后)。这个问题是对于C ++ 20都可以同时具有constexpr std::swap(在P0879中解决)和constexpr std::invoke(在P1065中也具有CWG1581示例)的阻碍。


3
投票

原因

(由于@NathanOliver)

为了允许constexpr交换功能,必须在实例化此函数的模板之前检查交换类型是否可移动构造和可分配移动。不幸的是,由于仅在C ++ 20中解决了语言缺陷,您无法对此进行了检查,因为相关的成员函数可能尚未生成/实例化。

年表

  • Antony Polukhin提交了提案P0202,以将所有<algorithm>功能标记为constexpr
  • 标准委员会的核心工作组意识到/讨论了缺陷CWG-1581。此问题使同时具有constexpr std::swapconstexpr std::invoke成为问题-请参阅上面的说明。
  • [Antony修改了他的提案,以排除std::swap和其他一些构造,并且这被C ++ 17接受。
  • [CWG-1581问题的决议以P0859的形式提交,并在2017年被标准委员会接受(但在C ++ 17发行后)。
  • [Antony在2017年末提交了补充提案P0879
  • 补充建议被接受(?),但这仅使它成为C ++ 20。正如Barry所指出的,constexpr std::invoke修复也是如此。

您的具体情况

如果您不要检查移动可构造性和移动可分配性,则可以使用constexpr交换,而是直接检查类型的某些其他功能,以确保尤其如此。例如仅原始类型,没有类或结构。或者,从理论上讲,您可以放弃检查,而仅处理可能遇到的任何编译错误,以及在编译器之间进行不稳定的行为切换。无论如何,不​​要用这种东西代替std::swap()

© www.soinside.com 2019 - 2024. All rights reserved.