问题
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