![](/img/trans.png)
[英]Why has std::accumulate not been made constexpr in C++20?
[英]Why isn't std::swap marked constexpr before C++20?
在 C++20 中, std::swap
变成了constexpr
函数。
我知道标准库在标记事物constexpr
方面确实落后于语言,但到 2017 年, <algorithm>
和其他一些东西一样,几乎都是 constexpr。 然而 - std::swap
不是。 我依稀记得有一些奇怪的语言缺陷阻止了那个标记,但我忘记了细节。
有人可以简洁明了地解释这一点吗?
动机:需要理解为什么在 C++11/C++14 代码中标记一个std::swap()
的函数constexpr
可能是个坏主意。
奇怪的语言问题是CWG 1581 :
第 15 条 [特殊] 非常清楚,特殊成员函数仅在 odr 使用时才隐式定义。 这给未计算上下文中的常量表达式带来了问题:
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 行,则隐式定义了移动构造函数并且程序有效。 这种远距离的诡异动作是极其不幸的。 在这一点上,实现存在分歧。
您可以阅读问题描述的其余部分。
2017 年在阿尔伯克基的P0859中(在 C++17 发布后)通过了针对此问题的解决方案。 这个问题是一个阻碍,因为它们都能够有一个constexpr std::swap
(在P0879 中解决)和一个constexpr std::invoke
(在P1065 中解决,它也有 CWG1581 示例),两者都适用于 C++20。
在我看来,这里最容易理解的示例是 P1065 中指出的 LLVM 错误报告中的代码:
template<typename T> int f(T x) { return x.get(); } template<typename T> constexpr int g(T x) { return x.get(); } int main() { // OK The body of `f' is not required. decltype(f(0)) a; // Seems to instantiate the body of `g' // and results in an error. decltype(g(0)) b; return 0; }
CWG1581 是关于何时定义 constexpr 成员函数的,并且决议确保它们仅在使用时被定义。 在 P0859 之后,以上是格式良好的( b
的类型是int
)。
由于std::swap
和std::invoke
都必须依赖于检查成员函数(前者中的移动构造/赋值和后者中的调用运算符/代理调用),因此它们都取决于此问题的解决方案。
(由于@NathanOliver)
要允许constexpr
交换函数,您必须检查 - 在实例化此函数的模板之前 - 交换的类型是可移动构造和可移动分配的。 不幸的是,由于仅在 C++20 中解决了语言缺陷,您无法检查它,因为就编译器而言,相关成员函数可能尚未定义。
<algorithm>
函数标记为constexpr
。constexpr std::swap()
和constexpr std::invoke()
- 请参阅上面的解释。std::swap
和其他一些结构,这被 C++17 接受。std::swap()
constexpr 。std::invoke()
修复也是如此。如果您不检查移动可构造性和移动可分配性,而是直接检查某些其他类型的特性,特别是确保这一点,则可以使用constexpr
交换。 例如,只有原始类型,没有类或结构。 或者,理论上,您可以放弃检查并只处理您可能遇到的任何编译错误,以及编译器之间的不稳定行为切换。 无论如何,不要用那种东西替换std::swap()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.