Recursive evaluation of consteval functions seem even more natural than using control flow structures for traversing parameter packs.
Recursion termination is done by providing a more specialized overload of the function.


On December 4, 2023 7:24:31 p.m. EST, Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Fold expressions are fantastic and it's great what we can do with
them. Sometimes though, some really simple operations turn into a
really complicated fold expression involving a template lambda. That
which could have been a very simple 'for' loop gets turned into a
pretty elaborate fold expression, possibly with a lambda and some
extra helper classes and helper functions to get the job done.

I'm not the first person to suggest that we should have "for..." in
the language, and so just to stir things up again, here's 3 possible
uses of it:

(1) Iterating over compile-time constants in a parameter pack

#include <cstddef> // size_t
template<std::size_t... indices>
consteval bool contains_multiple_of_eight(std::size_t const arg)
{
for... ( i : indices )
{
if ( 0u == (i % arg) ) return true;
}

return false;
}

(2) Iterating over runtime arguments

template<typename... Params>
consteval bool contains_at_least_one_true(Params&&... args)
{
for... ( arg : args )
{
if constexpr ( requires { static_cast<bool>(arg); } )
{
if ( static_cast<bool>(arg) ) return true;
}
}

return false;
}

(3) Iterating over types

template<typename... Params>
consteval bool
all_implicitly_convert_to_false_after_default_initialisation(void)
{
for typename... ( P : Params )
{
if constexpr ( !requires { static_cast<bool>( P{} ); } )
return false;
}

return true;
}

I'm not trying to argue here that these three examples are impossible
to implement with normal fold expressions. I'm saying that we could
write much more simple code if we had "for..." in the language.