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

标签 c++ c++11 constexpr c++20

在 C++20 中,std::swap变成 constexpr功能。

我知道标准库在标记事物方面确实落后于语言constexpr ,但到 2017 年,<algorithm>和其他一堆东西一样,几乎都是 constexpr。然而 - std::swap不是。我依稀记得有一些奇怪的语言缺陷阻止了那个标记,但我忘记了细节。

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

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

最佳答案

奇怪的语言问题是CWG 1581 :

Clause 15 [special] is perfectly clear that special member functions are only implicitly defined when they are odr-used. This creates a problem for constant expressions in unevaluated contexts:

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

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

The issue here is that we are not permitted to implicitly define constexpr duration::duration(duration&&) in this program, so the expression in the initializer list is not a constant expression (because it invokes a constexpr function which has not been defined), so the braced initializer contains a narrowing conversion, so the program is ill-formed.

If we uncomment line #1, the move constructor is implicitly defined and the program is valid. This spooky action at a distance is extremely unfortunate. Implementations diverge on this point.



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

P0859 中通过了针对此问题的解决方案2017 年在阿尔伯克基(在 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() {

  // O.K. 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::swapstd::invoke两者都必须依赖于检查成员函数(前者中的移动构造/赋值,后者中的调用运算符/代理调用),它们都取决于此问题的解决方案。

关于c++ - 为什么在 C++20 之前 std::swap 没有标记为 constexpr ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60674939/

相关文章:

c++ - 从 OpenGL 着色器获取数据?

c++ - c++中的编译错误是什么?

c++ - constexpr、static_assert 和内联

c++ - 捕获函数参数中的常量表达式

c++ - TODO 提醒 constexpr

c++ - DLL EXE 混合 C++ Windows

c++ - 超出范围指针的比较是否定义明确?

multithreading - timed_mutex 不会在 Cygwin 4.8.2 ('timed_mutex' 下编译,命名空间 'std' 没有命名类型)

c++ - 使用 asio 和 C++11 接受或接收时优雅地停止线程以进行阻塞或非阻塞

c++ - C++ 模板是否能够从父类获取 "forward any class function"?