In some contexts, it could be useful/necessary to have a for
loop evaluated/unrolled at compile time. For example, to iterate over the elements of a tuple
, one needs to use std::get<I>
, which depends on a template int
parameter I
, hence it has to be evaluated at compile time.
Using compile recursion one can solve a specific problem, as for instance discussed here, here, and, specifically for std::tuple
here.
I am interested, however, on how to implement a generic compile-time for
loop.
The following c++17
code implements this idea
#include <utility>
#include <tuple>
#include <string>
#include <iostream>
template <int start, int end, template <int> class OperatorType, typename... Args>
void compile_time_for(Args... args)
{
if constexpr (start < end)
{
OperatorType<start>()(std::forward<Args>(args)...);
compile_time_for<start + 1, end, OperatorType>(std::forward<Args>(args)...);
}
}
template <int I>
struct print_tuple_i {
template <typename... U>
void operator()(const std::tuple<U...>& x) { std::cout << std::get<I>(x) << " "; }
};
int main()
{
std::tuple<int, int, std::string> x{1, 2, "hello"};
compile_time_for<0, 3, print_tuple_i>(x);
return 0;
}
While the code works, it would be nicer to be able to simply provide a template function to the routine compile_time_for
, rather than a template class to be instantiated at each iteration.
A code like the following, however, does not compile in c++17
#include <utility>
#include <tuple>
#include <string>
#include <iostream>
template <int start, int end, template <int, typename...> class F, typename... Args>
void compile_time_for(F f, Args... args)
{
if constexpr (start < end)
{
f<start>(std::forward<Args>(args)...);
compile_time_for<start + 1, end>(f, std::forward<Args>(args)...);
}
}
template <int I, typename... U>
void myprint(const std::tuple<U...>& x) { std::cout << std::get<I>(x) << " "; }
int main()
{
std::tuple<int, int, std::string> x{1, 2, "hello"};
compile_time_for<0, 3>(myprint, x);
return 0;
}
With gcc 7.3.0 and option std=c++17
the first error is
for2.cpp:7:25: error: ‘auto’ parameter not permitted in this context
void compile_time_for(F f, Args... args)
The questions are:
- Is there a way to write
compile_time_for
such that it accepts a template function as its first argument? - If question 1. is positive, is there an overhead in the first working code, due to the fact that the routine create an object of type
OperatorType<start>
at every loop iteration? - Are there plans to introduce a feature like a compile-time for loop in the upcoming
c++20
?
std::index_sequence
andstd::make_index_sequence
? – Energeticstd::apply
:std::apply([](const auto&...args) { ((std::cout << args << " "), ...); }, x);
. – Everetteverettestd::appy
will not do the job if the operation to be done at each loop iteration depends on the iteration itself (via a template parameter, for instance) – Sellarsdecltype(args)
. C++20 would allow to have explicit template in lambda too, normally. – Everetteverettefor...(/*..*/)
. But I don't succeed to find it. – Everetteverette