康桓瑋
康桓瑋

Reputation: 42776

Why the return view of C++20 range adaptors is not a constant expression?

Consider the following code:

#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 accept it, gcc rejects it with:

<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);
      |                                            ^

Why does r is not a constant expression?

Upvotes: 5

Views: 247

Answers (1)

The ranges bit is a red herring. It can be boiled down to this

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

We cannot form a constexpr pointer to the first element of a. Such pointers are constrained to hold only the addresses of objects with static storage duration. The view object (as part of its implementation somewhere deep down) is going to need to keep a copy of an iterator (the pointer in our case).

Since r is declared constexpr and it internally holds a pointer to an object, that object too must have static storage duration. Indeed, modifying the code to contain

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

Makes GCC accept your example happily.

MSVC is non-conformant however. It accepts the invalid plain pointer example as well.

Upvotes: 5

Related Questions