As an alternative to @Yakk's answer, https://artificial-mind.net/blog/2020/10/31/constexpr-for gives a much simpler solution.
This requires c++17
template <auto Start, auto End, auto Inc = 1, typename F>
constexpr void constexpr_for(F&& f) {
static_assert(Inc != 0);
if constexpr ((Inc > 0 && Start < End) || (Inc < 0 && End < Start)) {
f(std::integral_constant<decltype(Start), Start>());
constexpr_for<Start + Inc, End, Inc>(f);
}
}
use:
constexpr_for<0,5>([&](auto i) { dostuff(i); });
//0,1,2,3,4
You can even alter it like so, so that it auto-deduces the begin and end.
template <auto Start, auto End = Start, auto Inc = 0, typename F>
constexpr void constexpr_for(F&& f) {
//sanity check for params
static_assert((Inc == 0) || (Inc > 0 && End > Start) || (Inc < 0 && Start > End));
//deduce direction from start and end if 2 params given
constexpr auto dir = (Inc != 0) ? Inc: (Start > End) ? -1 : 1;
//deduce first & last if only 1 param given
constexpr auto first = (Start == End) ? 0 : Start;
constexpr auto last = (Start == End) ? Start : End;
//next simplifies code later
constexpr auto next = first + dir;
//while not done, do loop_work
if constexpr ((dir > 0 && first < last) || ((dir < 0 && last < first))) {
//integral_constant makes first a constant expression
//calling `f(first)` gives error: "expr. must have constant value"
f(std::integral_constant<decltype(Start), first>());
//if the next loop will be valid...
if constexpr ((dir > 0 && next < last) || (dir < 0 && last < next)) {
//... run one more loop
constexpr_for<next, last, dir>(f);
}
}
}
use:
constexpr_for<4,-1>([&](auto i) { dostuff(i); }); // 4 3 2 1 0
constexpr_for<5>([&](auto i) {dostuff(i); }); //0 1 2 3 4
If you want to iterate over a parameter pack, overload the constexpr_for
as follows:
template <typename F, typename... Args>
constexpr void constexpr_for(F&& f, Args&&... args) {
(f(std::forward<Args>(args)), ...);
}
use:
template <class... Args>
void print_all(Args const&... args) {
constexpr_for([](auto const& v) {
std::cout << v << std::endl;
}, args...);
}
Further reading: https://vittorioromeo.info/index/blog/cpp20_lambdas_compiletime_for.html
if constexpr
in your code.. – Wherefromfor constexpr
– Cymbalfor constexpr
. I saw this discussion over it over on the std-proposals google group, though – Trigonous