首页 > 解决方案 > 为什么 C++20 范围适配器的返回视图不是常量表达式?

问题描述

考虑以下代码:

#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拒绝它:

<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不是常量表达式?

标签: c++c++20range-v3std-ranges

解决方案


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

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

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

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

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

GCC愉快地接受你的例子。

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


推荐阅读