Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 调用模板布尔函数的最佳方法_C++_Templates - Fatal编程技术网

C++ 调用模板布尔函数的最佳方法

C++ 调用模板布尔函数的最佳方法,c++,templates,C++,Templates,我有一个这样的函数 template<bool switch1, bool switch2, bool switch3> void foo(){ } inline void call_foo(bool switch1, bool switch2, bool switch3){ if (switch1 && switch2 && switch3) foo<true, true, true>(); else i

我有一个这样的函数

template<bool switch1, bool switch2, bool switch3>
void foo(){
}
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
}
模板
void foo(){
}
我这样定义函数是因为我想让编译器生成8个不同的(希望是高度优化的)函数版本。然而,现在当调用函数时,我必须这样做

template<bool switch1, bool switch2, bool switch3>
void foo(){
}
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
}
内联无效调用\u foo(bool开关1、bool开关2、bool开关3){
如果(开关1和开关2和开关3)
foo();
如果(!switch1&&switch2&&switch3)
foo();
//还有6个如果
}
有没有更优雅的方法


注意:我知道我可以跳过模板参数。但是在分析这两个版本的代码时,我发现模板化代码的速度有了显著的提高。

对于优雅的定义,映射会更优雅:

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]();
std::地图调度{
{{false,false,false},foo},
///
{{true,true,true},foo}
};
std::数组到{{switch1,switch2,switch3};
派遣[到]();

如果您喜欢可变模板,可以通过以下方式实现:

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);
}
模板
结构调度器
{
静态void调用(){
foo();
}
模板
静态无效调用(布尔b,Args1…ar1){
如果(b)
调度器::呼叫(ar1…);
其他的
调度器::呼叫(ar1…);
}
};
无效呼叫(布尔a、布尔b、布尔c)
{
调度器::呼叫(a、b、c);
}

类似于地图,您可以使用数组:

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]();
const std::数组调度{
&富和富,
&富和富,
&富和富,
&富和富,
};
dispatch[switch1Jarod42的查找表解决方案可能是最快、最简单的,但为了完整起见,可能需要对原始代码进行或多或少的逐字替换

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>{} );
模板
无效调用\u foo(布尔开关1、布尔开关2、布尔开关3、std::索引\u序列)
{
if(开关1==bool(I&1)和开关2==bool(I&2)和开关3==bool(I&4))
foo();
如果constexpr(sizeof…(Is)>0)
调用_foo(switch1、switch2、switch3、std::index_序列{});
}
//用作
调用_foo(true,false,true,std::make_index_sequence{});
使用额外的索引_序列,这也可以推广到任意布尔计数

采用函子的完全通用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 );
template
void untemplatize_impl(F&&F,std::index_序列位,std::index_序列,T…bools)
{

如果(I==((unsigned(bools)Expression)SFINAE可能是“模板化代码的速度显著提高”。我怀疑是其他原因导致了速度上的差异。在运行的代码中没有模板……评测时,您是否使用了优化构建(
-O2
编译器选项或类似选项),并且您是否将非模板函数定义为
内联
(您应该显示该代码)?我使用的是
-O3
。我还在代码中添加了
内联
。在任何情况下,我优化的是
foo
中循环内的开关检查,用函数外的单个检查代替。OP似乎在寻求最大性能。这不是实现这一点的方法。@JohnZwinck-(1)OP提到了
foo
本身的性能在模板化时得到了提高。我没有收集到他们寻求“最大”性能(因为该分支本身是次优的)。(2)OP可以使用这个和
std::unordered_map
。他们需要配置文件以了解他们的目标是否实现。(3)他们要求优雅。实际上比简单的地图要好。可能会被优化到最低限度。我想你应该把下面的调度器称为
dispatcher
(或
false
);如果调用
false,Args…
则必须颠倒
call\u foo
的参数顺序;额外建议:如果
call()
方法是
static
,则没有理由创建
dispatcher
类型的对象;只需调用
dispatcher::call(…);
@max66谢谢你的建议,刚刚修复了它。我更喜欢其他答案,但这个答案有一个优点:也适用于假设的
foo()
,具有可变的booleat模板值列表;+1。我肯定认为这个解决方案赢得了优雅。特别是因为它可以很容易地推广到更多的
bool
s