I'd like to write something like that :
template<int i> void f() {}
for (constexpr int i : {1,2,3})
{
f<i>();
}
Is it possible to iterate on constexpr ?
Thank you
As you probably understand, you cannot do the like of:
for (constexpr int i : {1,2,3})
{
f<i>();
}
because, if i
is to vary from 1 through 3 in a loop, then it is a variable and
not a compiletime constant. And a variable cannot be a template argument,
as in f<i>
: only a compiletime constant can be a template argument.
In C++11 and later, thanks to variadic templates, you can effectively iterate over an arbitary sequence of compiletime constants by using compiletime recursion of a template function that accepts a suitable arbitrary sequence of template arguments.
That will hardly mean anything to you if you don't already know how to do it. Here is a C++11 example that does what you want to express:
#include <type_traits>
#include <iostream>
template<int i> void f()
{
std::cout << i << '\n';
}
// This overload is chosen when there is only 1 template argument.
template<int First, int ...Rest>
typename std::enable_if<sizeof...(Rest) == 0>::type
for_each_f()
{
f<First>();
}
// This overload is chosen when there is > 1 template argument.
template<int First, int ...Rest>
typename std::enable_if<sizeof...(Rest) != 0>::type
for_each_f()
{
f<First>();
for_each_f<Rest...>();
}
int main()
{
for_each_f<2,3,5,7,11>();
return 0;
}
See it live
Besides variadic templates, this technique depends on the very important C++ meta-programming
principle of SFINAE, and on std::enable_if
,
which is the tool that the Standard C++ library provides for exploiting SFINAE.
101010's answer demonstrates a more sophisticated and powerful style of solution that is available in C++14 (and easy enough to implement in C++11 if you write some supporting boilerplate).
No you can't use a for loop to iterate over at compile time. The for control structure in C++ is used for runtime control flow.
However, you could use other compile time facilities. For example in C++ 14 you could achieve what you want in the following manner:
Define a template wrapper class that's gonna call your function.
template<int i> struct wrapper { void operator()() const { f<i>(); } };
Use std::index_sequence to generate compile time indices.
template<template<int> class W, std::size_t... I> void caller_impl(std::index_sequence<I...>) { int t[] = { 0, ((void)W<I>()(), 1)... }; (void) t; } template<template<int> class W, std::size_t N, typename Indices = std::make_index_sequence<N>> void call_times() { caller_impl<W>(Indices()); }
Then call as
int main() { call_times<wrapper, 42>(); }
Live Demo
If C++14 is not an option you could take a look here of how you could implement std::index_sequence
your self.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With