apo
apo

Reputation: 75

Best way to handle 2+ template parameters?

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

Answers (2)

yuri kilochek
yuri kilochek

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

Vittorio Romeo
Vittorio Romeo

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);
}

wandbox example


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

Related Questions