This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 118f. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-11-19
(From submission #805.)
Consider:
#include <span>
constexpr int arr[3] = { 1, 2, 3 };
consteval std::span<const int> foo() {
return std::span<const int>(arr);
}
int main() {
int r = 0;
template for (constexpr auto m : foo())
r += m;
}
The expansion of this iterable expansion statement contains:
constexpr auto &&range = foo();
The deduction yields std::span<const int>&& for the type of range, and the non-const lifetime-extended temporary causes constant evaluation to fail.
Furthermore, in order to allow expansion over non-constant std::array (which does have a compile-time size), the constexpr in the range declaration should be optional, similar to the destructuring case.
Possible resolution:
Change in 8.7 [stmt.expand] bullet 5.2 as follows:
- ...
- Otherwise, if S is an iterating expansion statement, S is equivalent to:
{ init-statement constexproptwhere N is the result of evaluating the expressionauto&&decltype(auto) range = (expansion-initializer) ; constexpr auto begin = begin-expr; // see 8.6.5 [stmt.ranged] constexpr auto end = end-expr; // see 8.6.5 [stmt.ranged] S0 . . . SN-1 }[&] consteval { std::ptrdiff_t result = 0;and Si isfor (auto i = begin ; i != end ; ++i, ++result);auto b = begin-expr ; auto e = end-expr ; for (; b != e; ++b) ++result; return result; // distance from begin to end }(){ static constexpr auto iter = begin + i; for-range-declaration = *iter ; compound-statement }The variables range, begin, end, and iter are defined for exposition only. The keyword constexpr is present in the declaration of range if and only if constexpr is one of the decl-specifiers of the decl-specifier-seq of the for-range-declaration.[Note 1: The instantiation is ill-formed if range is not a constant expression (7.7 [expr.const]). —end note]- ...