我有这样的功能
template<bool switch1, bool switch2, bool switch3>
void foo(){
}
我定义了这样的函数,因为我希望编译器生成8个不同的(希望大大优化)函数版本。但是,现在调用函数时我必须做这样的事情
inline void call_foo(bool switch1, bool switch2, bool switch3){
if (switch1 && switch2 && switch3)
foo<true, true, true>();
else if (!switch1 && switch2 && switch3)
foo<false, true, true>();
// 6 more ifs
}
有更优雅的方式吗?
注意:我知道我可以跳过模板参数。但是对这两个版本的代码进行分析后,我发现使用模板化代码可以显着提高速度。
答案 0 :(得分:3)
对于优雅的定义,地图会更优雅:
std::map<std::array<bool,3>, void(*)()> dispatch {
{{false, false, false}, foo<false, false, false>},
///
{{true, true, true}, foo<true, true, true>}
};
std::array<bool, 3> to{ {switch1, switch2, switch3} };
dispatch[to]();
答案 1 :(得分:3)
如果您喜欢可变参数模板,可以这样实现:
template<bool ...Args>
struct dispatcher
{
static void call(){
foo<Args...>();
}
template<class ...Args1>
static void call(bool b, Args1... ar1){
if (b)
dispatcher<Args..., true>::call(ar1...);
else
dispatcher<Args..., false>::call(ar1...);
}
};
void call_foo(bool a, bool b, bool c)
{
dispatcher<>::call(a,b,c);
}
答案 2 :(得分:3)
与map类似,您可以使用array:
const std::array<void (*)(), 8> dispatch {
&foo<false, false, false>, &foo<false, false, true>,
&foo<false, true, false>, &foo<false, true, true>,
&foo<true, false, false>, &foo<true, false, true>,
&foo<true, true, false>, &foo<true, true, true>,
};
dispatch[switch1 << 2 | switch2 << 1 | switch3]();
答案 3 :(得分:0)
Jarod42 的查找表解决方案可能是最快最简单的,但为了完整起见,或多或少逐字替换原始代码可能
template< std::size_t I, std::size_t... Is >
void call_foo( bool switch1, bool switch2, bool switch3, std::index_sequence<I,Is...> )
{
if( switch1 == bool(I&1) && switch2 == bool(I&2) && switch3 == bool(I&4) )
foo<bool(I&1),bool(I&2),bool(I&4)>();
if constexpr( sizeof...(Is) > 0 )
call_foo( switch1, switch2, switch3, std::index_sequence<Is...>{} );
}
// to be used as
call_foo( true, false, true, std::make_index_sequence<2*2*2>{} );
使用额外的index_sequence,这也可以推广到任意bools计数。
采用仿函数的完全通用的c ++ 17版本可能如下所示:
template< class F, class... T, std::size_t... Js, std::size_t I, std::size_t... Is >
void untemplatize_impl( F&& f, std::index_sequence<Js...> bits, std::index_sequence<I,Is...>, T... bools )
{
if( I == ( ( unsigned(bools)<<Js ) | ... ) )
std::forward<F>(f).template operator()<bool(I&(1<<Js))...>();
if constexpr( sizeof...(Is) > 0 )
untemplatize_impl( std::forward<F>(f), bits, std::index_sequence<Is...>{}, bools... );
}
template< class F, class... T > // SFINAEd, if needed
void untemplatize( F&& f, T... bools )
{
untemplatize_impl( std::forward<F>(f), std::make_index_sequence<sizeof...(T)>{}, std::make_index_sequence<(1u<<sizeof...(T))>{}, bools... );
}
// to be used as
untemplatize( foo{}, false, true, true );
同样可以在c ++ 11中使用,但更麻烦。