Date: Tue, 5 Dec 2023 00:24:31 +0000
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.
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.
Received on 2023-12-05 00:24:44