Draxent
Draxent

Reputation: 520

c++ bool template avoiding if statement

I'm looking a way to avoid if-statement when I'm dealing with template bool function.
Code below shows a simplification of my situation.

#include <iostream>
#include <string>

template<bool var>
void f(){
 std::cout << (var ? "TRUE" : "FALSE") << std::endl;
}

int main(int argc, char* argv[]){
    const bool b = (std::string(argv[1]).compare("TRUE") == 0);
    if (b) f<true>();
    else f<false>();
    return 0;   
}

I don't want to pass b as parameter of function f() because, in the real application, I am interested in performance and I need to check the value of b in a critical code section.
I would like a way to write something like: f<b>();
But doing so, I obtain the following error:
error: the value of ‘b’ is not usable in a constant expression

Since in my application I have 4 bool templates, I would like to avoid to list all the combination of those four, like:

if(b1 && b2 && b3 && b4) f<true,true,true,true>();
else if (b1 && b2 && b3 && !b4) f<true,true,true,false>();
...

There is a way around? Does exists a shortcut that I can use in some way?
I tried also to use the if-statement shortcut f<(b?true:false)>();,
but I received the same error shows above.

Upvotes: 0

Views: 2052

Answers (2)

Jarod42
Jarod42

Reputation: 217065

You might want something like:

template <bool b1, bool b2, bool b3, bool b4>
void f()
{
    // Your method.
    std::cout << b1 << b2 << b3 << b4 << std::endl;   
}

template <std::size_t...Is>
void call_f_helper(int i, std::index_sequence<Is...>)
{
    using f_t = void();
    f_t* fs[] = {&f<(Is >> 0) & 1, (Is >> 1) & 1, (Is >> 2) & 1, (Is >> 3) & 1>...};

    fs[i]();
}

// The runtime dispather
void call_f(bool b1, bool b2, bool b3, bool b4)
{
    call_f_helper(b1 << 0 | b2 << 1 | b3 << 2 | b4 << 3, std::make_index_sequence<16>());  
}

Demo

Upvotes: 3

Edward Strange
Edward Strange

Reputation: 40849

I think I understand what you want to do. You want a lookup table that takes a bunch of on/off flags and runs a specific instantiation of a template...

It's possible but a bit beyond what can just be done in a quick answer. You'll need some moderate metaprogramming. Where I'd start is:

  1. Implement a metaprogram that creates a set of permutations of n flags.
  2. Implement a constexpr function that converts a series of flags into a bitmask. You'll use it both at runtime and compile-time.
  3. Implement a metaprogram that will give you a function pointer to the instantiation based on bool flags.
  4. Implement a metaprogram/constexpr function that generates an array of such pointers indexed by the bitmask.
  5. Call at runtime with your boolean values.

It will probably take a couple hours to implement but shouldn't be THAT hard.

What your original question seemed to expect was converting a runtime value into a compile-time value and that's simply impossible. But you can implement a jump table such that you don't have to hand write each permutation yourself. You should ask yourself though whether it's really worthwhile because the end result is going to be harder to maintain, especially if your team is full of junior devs--which I am assuming at this point you are. A lot of senior devs run for the hills on seeing this kind of thing too.

Oh, and you're not necessarily going to see any performance improvement at all. Profile, don't assume.

Upvotes: 2

Related Questions