How to launch a function template with many boolean arguments without 2^n if statements

↘锁芯ラ 提交于 2020-01-11 10:46:14

问题


I have a CUDA (C++) code that uses function templates exclusively for performance reasons, so that the function will do only what it needs to do and not constantly be loading and reading booleans to check wether it needs to do stuff or not.

All template arguments are booleans. At launch of the kernel the CPU checks the values of the booleans and launches the appropriate, I believe it's called, "instantiation" of the kernel template. I understand this gives exponential code size growth but my question is about something else: Launching the kernel template involves 2^n if statements, is there a smarter syntax to this?

For example if n=2:

if(bool1){
    if(bool2){
        <true,true>func();
    }
    else{
        <true,false>func();
    }
}
else{
    if(bool2){
        <false,true>func();
    }
    else{
        <false,false>func();
    }
}

When n=10 it becomes just unacceptable, is there a syntax to avoid such horrors?

For example I tried <bool1 ? true:false,bool2 ? true:false>func() but the compiler didn't like it...

Change boolean flags into template arguments seems to talk about a similar issue but the OP has more than just booleans and the solution offered looks worse than the problem to me, and frankly I don't understand a word of it.


回答1:


You could add an overload to func like this:

template< bool... Bs >
void func()
{
    // Implement func with compile-time Bs...
}

template< bool... Bs, typename... Ts >
void func( bool b, Ts... ts )
{
    if( b ) {
        func< Bs..., true >( ts... );
    }
    else {
        func< Bs..., false >( ts... );
    }
}

int main()
{
    // call func< true, false, true, true >();
    func( true, false, true, true );
}

It works by converting the run-time boolean parameters into compile-time parameters one-by-one recursively.

Live example




回答2:


It's fairly straightforward once you get the hang of variadic template expansions.

this code builds a vector of each version of a function with 3 binary compile-time options. The index into the vector is the integer value of considering those options as binary bits:

#include <iostream>
#include <functional>
#include <vector>

using namespace std;

// the actual function implementation 
template <bool option_a, bool option_b, bool option_c>
void function_with_options()
{
    if(option_a)
        cout << "option a is enabled, ";
    else
        cout << "no option a, ";

    if(option_b)
        cout << "option b is enabled, ";
    else
        cout << "no option b, ";

    if(option_c)
        cout << "option c is enabled, ";
    else
        cout << "no option c, ";
}


// convert an integer into the 3 option bits and return a corresponding function object 
template<int bits>
std::function<void()>
make_function_with_options()
{
    return function_with_options<bool(bits & 1), bool(bits & 2), bool(bits & 4)>;
}

// expand an index sequence of make_function_with_options<int>
template<size_t... Is>
std::vector<std::function<void()>>
make_all_functions_impl(std::index_sequence<Is...>)
{
    auto v = std::vector<std::function<void()>> { make_function_with_options<Is>()... };
    return v;
}

// make an ordered vector of the 8 function variants     
std::vector<std::function<void()>>
make_all_functions()
{
    return make_all_functions_impl(make_index_sequence<8>{});
}

// here is my global 'switch'
static const std::vector<std::function<void()>> bit_functions = make_all_functions();

int main()
{

    // call each 'switch' option to prove it works    
    for(size_t i = 0 ; i < bit_functions.size() ; ++i)
    {
        cout << "case " << i << " ";
        bit_functions[i]();
        cout << endl;
    }

    return 0;
}

output:

case 0 no option a, no option b, no option c, 
case 1 option a is enabled, no option b, no option c, 
case 2 no option a, option b is enabled, no option c, 
case 3 option a is enabled, option b is enabled, no option c, 
case 4 no option a, no option b, option c is enabled, 
case 5 option a is enabled, no option b, option c is enabled, 
case 6 no option a, option b is enabled, option c is enabled, 
case 7 option a is enabled, option b is enabled, option c is enabled, 



回答3:


Encode each boolean to a bit in a number, then use a switch statement. Something like this to set bits:

int i = 0;
i = i | ((1 << (N-1)) && boolN);


来源:https://stackoverflow.com/questions/27564994/how-to-launch-a-function-template-with-many-boolean-arguments-without-2n-if-sta

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!