Reputation: 42776
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
Reputation: 170074
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