处理 2+ 模板参数的最佳方法

Best way to handle 2+ template parameters?

本文关键字:最佳 方法 参数 处理      更新时间:2023-10-16

假设我有一个以下形式的模板化函数:

template<bool a, bool b, bool c>
void foo(){
   if(a) printf("I do something when a is true!n");
   if(b) printf("I do something when b is true!n");
   if(c) printf("I do something when c is true!n");
}

现在我有了这个函数,它可以专门针对 8 种可能情况中的每一种进行编译(a = b = c = true,a=b = true c=false 等)。

我想用运行时获得的 a、b 和 c 值调用这个函数。

如果模板只有一个参数,我可以做:

void caller(bool a){
   if(a) foo<true>();
   else  foo<false>();
}

但是,如果您有 2+ 个参数怎么办?你不能只做:

void caller(bool a, bool b, bool c){
   foo<a,b,c>();
}

如果你用if-else/switch来做,那种随意的疯狂是不可取的。我想让编译器编译 foo 的 8 个版本,然后调用

foo<a,b,c>()

如果相反,我可以做出类似的情况,我有:

template<int a>
void foo(){
   printf("%d", a);
} 

假设我知道 a 可以在 0 和 32 之间变化。我想做这样的事情:

void caller(int a){
   if(a<=32 && a>0) foo<a>();
   else printf("ERROR!/n");
}

处理这种情况的最佳方法是什么?

但是,如果您有 2+ 个参数怎么办?你不能只做:

您可以使用可变参数模板、递归、高阶函数和std::integral_constant

template <typename TF>
auto with_bool_constant(TF xf)
{
    return xf();
};
template <typename TF, typename T, typename... Ts>
auto with_bool_constant(TF xf, T x, Ts... xs)
{
    if(x) 
        return with_bool_constant([&](auto... ys)
                                  { xf(std::integral_constant<bool, true>{}, ys...); }, 
                                  xs...);
    else 
        return with_bool_constant([&](auto... ys)
                                  { xf(std::integral_constant<bool, false>{}, ys...); }, 
                                  xs...);
};

用法:

template <bool a, bool b, bool c>
void f() 
{ 
    std::cout << std::boolalpha << a << " " << b << " " << c << "n"; 
}
int main()
{
    auto f_wrapper = [](auto a, auto b, auto c)
    {
        return f<a, b, c>();
    };
    with_bool_constant(f_wrapper, true, false, true);
}

魔杖盒示例


假设我知道 a 可以在 0 和 32 之间变化。我想做这样的事情:

可以使用boost::hana::make_range生成0...32编译时范围(必须在编译时知道边界)。然后,您可以使用boost::hana::for_each或类似的编译时迭代构造将运行时值转换为std::integral_constant<int, X>,并将类似的技术应用于我上面发布的技术。

你有正确的想法,你只需要对每个参数准递归地这样做:

#include <cstdio>
template <bool a, bool b, bool c>
void foo() {
     if(a) printf("I do something when a is true!n");
     if(b) printf("I do something when b is true!n");
     if(c) printf("I do something when c is true!n");
}
template <bool... bs>
void caller() {
    foo<bs...>();
}
template <bool... cbs, typename... RBS>
void caller(bool rb0, RBS... rbs) {
    if (rb0) {
        caller<cbs..., true>(rbs...);
    } else {
        caller<cbs..., false>(rbs...);
    }
}
int main() {
     caller(true, false, true);
}