std::ranges::sort is not usable as a 'constexpr' function when saving its return value in lambda function

Viewed 210

This function f can take C++20 ranges algorithm objects as an argument then use it:

constexpr auto f(auto algo) {
  return [=] {
    algo(std::array{1, 0});
    return true;
  }();
}

and it works fine with std::ranges::sort:

static_assert(f(std::ranges::sort));

But when I save the return value of algo in the lambda:

constexpr auto f(auto algo) {
  return [=] {
    auto it = algo(std::array{1, 0});
    return true;
  }();
}

GCC rejects and says:

<source>:10:16: error: non-constant condition for static assertion
   10 | static_assert(f(std::ranges::sort));
      |               ~^~~~~~~~~~~~~~~~~~~
<source>:10:16: error: 'constexpr auto f(auto:16) [with auto:16 = std::ranges::__sort_fn]' called in a constant expression
<source>:3:16: note: 'constexpr auto f(auto:16) [with auto:16 = std::ranges::__sort_fn]' is not usable as a 'constexpr' function because:
    3 | constexpr auto f(auto algo) {
      |                ^
<source>:7:4: error: call to non-'constexpr' function 'f<std::ranges::__sort_fn>::<lambda()>'
    4 |   return [=] {
      |          ~~~~~
    5 |     auto it = algo(std::array{1, 0});
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    6 |     return true;
      |     ~~~~~~~~~~~~
    7 |   }();
      |   ~^~
<source>:4:10: note: 'f<std::ranges::__sort_fn>::<lambda()>' is not usable as a 'constexpr' function because:
    4 |   return [=] {
      |          ^

Why this function becomes non-'constexpr' when I try to save algo's return value? or it just a bug?

Update: The following code will be accepted by GCC so this is most likely a bug and I already filed a bug report.

constexpr auto f(auto algo, auto... args) {
  return [=] () mutable {
    auto it = algo(args...);
    return true;
  }();
}

// those are ok
static_assert(f(std::ranges::reverse, std::array{0})); 
static_assert(f(std::ranges::fill, std::array{0}, 0));
// those are not ok
// static_assert(f(std::ranges::sort, std::array{0}));    
// static_assert(f(std::ranges::replace, std::array{0}, 0, 0)); 
// static_assert(f(std::ranges::unique, std::array{0}));
// static_assert(f(std::ranges::next_permutation, std::array{0}));
// static_assert(f(std::ranges::prev_permutation, std::array{0}));
1 Answers

It works for me, if I declare the iterator it to be constexpr:

constexpr auto it = algo(std::array{1, 0});
Related