Reputation: 123
I would like to call a template function foo
with a sequence of different (non-type) parameters, taking consecutive integer values between a lower and upper bound. For instance:
template <int K> void foo(){ ... }
int const UPPER = 10, LOWER = 5;
for(int i = LOWER; i <= UPPER; i++)
foo<i>();
This, of course, won't work since i
is not known at compile time. I am looking for a way to achieve this sort of program without having to write something like:
foo<5>(); foo<6>(); foo<7>(); foo<8>(); foo<9>(); foo<10>();
This is in particular because I intend on changing UPPER
and LOWER
from one execution to the next.
My only idea was to create a constant array of the integers which will be sent to the template parameter:
int const arr[6] = {5, 6, 7, 8, 9, 10};
for(int i = LOWER; i <= UPPER; i++)
foo<arr[i]>();
But, again, although the elements of the array are constant, i
is not known at compile-time so neither is arr[i]
. Any suggestions?
Thank you in advance.
Upvotes: 0
Views: 1860
Reputation: 703
As far as I know templates are resolved to actual structures during compile time, so you you will have to pass int
as a argument to function.
Upvotes: 0
Reputation: 1602
You can use two templates and std::enable_if
to select one of them, depending on whether Lower
is equal to Upper
.
In case they are equal, we do nothing. Otherwise, we invoke foo<Lower>()
and recurse with parameters Lower + 1
and Upper
.
template <int Lower, int Upper>
typename std::enable_if<Lower == Upper, void>::type callFoo()
{
}
template <int Lower, int Upper>
typename std::enable_if<Lower != Upper, void>::type callFoo()
{
static_assert(Lower < Upper, "Lower must be less than or equal to Upper");
foo<Lower>();
callFoo<Lower + 1, Upper>();
}
Given this template, the following line will invoke foo<K>()
for K
values 5
, 6
, 7
, 8
, 9
, 10
.
callFoo<5, 11>();
Upvotes: 3
Reputation: 61920
You can make use of std::integer_sequence
to get a compile-time list of numbers from 0 ascending and then add your offset:
// Here we take the lower bound and the sequence 0 to (Upper - Lower).
// We call foo with each number in the sequence added to the lower bound.
template<int Lower, int... Ints>
void call_foo_with_range_helper(std::integer_sequence<int, Ints...>) {
// A common trick to expand the parameter pack without recursion or fold expressions
(void)std::initializer_list<int>{(foo<Lower + Ints>(), 0)...};
}
// This simply makes it easier for the caller to use.
// We take the lower and upper bounds only.
template<int Lower, int Upper>
void call_foo_with_range() {
call_foo_with_range_helper<Lower>(std::make_integer_sequence<int, Upper - Lower + 1>());
}
int main() {
int const UPPER = 10, LOWER = 5;
call_foo_with_range<LOWER, UPPER>();
}
Upvotes: 3