Reputation: 75
Say I have a templated function in the following form:
template<bool a, bool b, bool c>
void foo(){
if(a) printf("I do something when a is true!\n");
if(b) printf("I do something when b is true!\n");
if(c) printf("I do something when c is true!\n");
}
Now I have this function that can be compile time specialized for each of the 8 possibles cases (a = b = c = true, a=b=true c=false, etc etc).
I would like to call this function with values of a, b and c obtained on run time.
If the template had only one parameter I could do:
void caller(bool a){
if(a) foo<true>();
else foo<false>();
}
But what if you have 2+ parameters? You cannot just do:
void caller(bool a, bool b, bool c){
foo<a,b,c>();
}
And the casuistic madness if you do it with if-else/switch is undesirable. I would like for the compiler to compile the 8 versions of foo and just call
foo<a,b,c>()
An equivalent situation can be made if instead bool I have:
template<int a>
void foo(){
printf("%d", a);
}
Say that I know that a can vary between 0 and, i.e, 32. I would like to do something like:
void caller(int a){
if(a<=32 && a>0) foo<a>();
else printf("ERROR!/n");
}
What would be the best way to handle these kind of situations?
Upvotes: 3
Views: 172
Reputation: 13484
You've got the right idea, you just have to do it quasirecursively for every parameter:
#include <cstdio>
template <bool a, bool b, bool c>
void foo() {
if(a) printf("I do something when a is true!\n");
if(b) printf("I do something when b is true!\n");
if(c) printf("I do something when c is true!\n");
}
template <bool... bs>
void caller() {
foo<bs...>();
}
template <bool... cbs, typename... RBS>
void caller(bool rb0, RBS... rbs) {
if (rb0) {
caller<cbs..., true>(rbs...);
} else {
caller<cbs..., false>(rbs...);
}
}
int main() {
caller(true, false, true);
}
Upvotes: 2
Reputation: 93314
But what if you have 2+ parameters? You cannot just do:
You can use variadic templates, recursion, higher-order functions and std::integral_constant
:
template <typename TF>
auto with_bool_constant(TF xf)
{
return xf();
};
template <typename TF, typename T, typename... Ts>
auto with_bool_constant(TF xf, T x, Ts... xs)
{
if(x)
return with_bool_constant([&](auto... ys)
{ xf(std::integral_constant<bool, true>{}, ys...); },
xs...);
else
return with_bool_constant([&](auto... ys)
{ xf(std::integral_constant<bool, false>{}, ys...); },
xs...);
};
Usage:
template <bool a, bool b, bool c>
void f()
{
std::cout << std::boolalpha << a << " " << b << " " << c << "\n";
}
int main()
{
auto f_wrapper = [](auto a, auto b, auto c)
{
return f<a, b, c>();
};
with_bool_constant(f_wrapper, true, false, true);
}
Say that I know that a can vary between 0 and, i.e, 32. I would like to do something like:
You can use boost::hana::make_range
to generate a 0...32
compile-time range (the bounds must be known at compile time). You can then use boost::hana::for_each
or a similar compile-time iteration construct to convert a runtime value to std::integral_constant<int, X>
and apply a similar technique to the one I posted above.
Upvotes: 5