【问题标题】:Why the return view of C++20 range adaptors is not a constant expression?为什么 C++20 范围适配器的返回视图不是常量表达式?
【发布时间】:2021-06-21 23:16:33
【问题描述】:

考虑以下代码:

#include <ranges>

int main() {
  constexpr int a[] = {1, 2, 3, 4};
  constexpr auto r = a | std::views::take(3);
  static_assert(*r.begin() == 1);
}

msvc 接受它,gcc rejects 它与:

<source>:5:44: error: 'std::ranges::take_view<std::ranges::ref_view<const int [4]> >{3, std::ranges::ref_view<const int [4]>{(& a)}}' is not a constant expression
    5 |   constexpr auto r = a | std::views::take(3);
      |                                            ^

为什么r 不是常量表达式?

【问题讨论】:

  • clang 也不喜欢这段代码,只是略有不同。似乎在抱怨 a 不是数组?我不知道那里发生了什么。
  • @dratenik clang 尚未实现 P0896R4

标签: c++ c++20 range-v3 std-ranges


【解决方案1】:

范围位是一个红鲱鱼。可以归结为这个

int main() {
  constexpr int a[] = {1, 2, 3, 4};
  constexpr auto r = a ;
}

我们无法形成指向a 的第一个元素的constexpr 指针。此类指针被限制为仅保存具有静态存储持续时间的对象的地址。视图对象(作为其实现的一部分)需要保留一个迭代器的副本(在我们的例子中是指针)。

由于r 被声明为constexpr 并且它在内部拥有一个指向对象的指针,因此该对象也必须具有静态存储持续时间。确实,修改代码以包含

static constexpr int a[] = {1, 2, 3, 4};

GCC accept 成为你的榜样。

但是,MSVC 不符合要求。它也接受无效的普通指针示例。

【讨论】:

  • “此类指针被限制为仅保存具有静态存储持续时间的对象的地址”您能否详细说明为什么需要这样做,即使对象是具有相同范围的 constexpr?
  • @KarlKnechtel - constexpr 的对象仅使其可用于常量表达式。它仍然具有自动存储持续时间,如果使用 ODR,地址将“在堆栈上”。也许违反直觉,但你有它。对于要成为 constexpr 的指针,它必须保存一个即使在抽象机器中也是“已知”的值。只有静态对象的地址不会“移位”。
  • 哦,我明白你的意思了。因为a 会在堆栈上,所以在编译时无法确定其地址。
猜你喜欢
  • 1970-01-01
  • 2022-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-13
  • 1970-01-01
  • 2022-10-08
相关资源
最近更新 更多