如何在没有2 ^ n if语句的情况下启动具有许多布尔参数的函数模板

时间:2014-12-19 11:20:37

标签: c++ templates syntax

我有一个CUDA(C ++)代码,它仅出于性能原因使用函数模板,因此该函数将只执行它需要做的事情,而不是经常加载和读取布尔值以检查是否需要执行某些操作

所有模板参数都是布尔值。在启动内核时,CPU会检查布尔值并启动相应的值,我相信它被称为内核模板的“实例化”。我理解这会给出指数代码大小的增长,但我的问题是关于其他事情:启动内核模板涉及2 ^ n if语句,是否有更聪明的语法?

例如,如果n = 2:

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

当n = 10时,它变得不可接受,是否有语法来避免这种恐怖?

例如我试过了 <bool1 ? true:false,bool2 ? true:false>func()但是编译器不喜欢它......

Change boolean flags into template arguments似乎谈论了一个类似的问题,但是OP不仅仅是布尔,并且提供的解决方案对我来说看起来比问题更糟糕,坦率地说,我不明白它的一个词。

3 个答案:

答案 0 :(得分:9)

你可以像这样添加func的重载:

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

它的工作原理是将运行时布尔参数逐个转换为编译时参数。

Live example

答案 1 :(得分:2)

一旦你掌握了可变参数模板的扩展,这是相当简单的。

此代码使用3个二进制编译时选项构建函数的每个版本的向量。向量索引是将这些选项视为二进制位的整数值:

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

输出:

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, 

答案 2 :(得分:0)

将每个布尔值编码为数字中的一位,然后使用switch语句。像这样设置位:

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