假设我有2个函数对参数执行完全相同的操作,但使用不同的常量集来执行此操作。对于一个过于简单的例子:
int foo1(int x){
return 3+4*x
}
int foo2(int x){
return 6-4*x
}
在实际应用程序中假设会有多个参数和常量/文字,当然计算会复杂得多。 为了简单起见以及可维护性,我想将这两个函数重写为可以生成这两个函数的模板,以便我可以调用foo< 1>或者foo< 2>并将生成适当的功能。我知道我可以这样做:
int foo(int x, int funcType){
const int firstConst = (funcType==1) ? 3 : 6;
const int secondConst = (funcType==1) ? 4 : -4;
return firstConst+secondConst*x;
}
但是因为我总是在编译时知道我想要使用哪个函数,所以我想使用模板来避免分支。有没有办法做到这一点?
答案 0 :(得分:3)
您可以使用traits类模板分别管理常量/文字,例如
template <int FuncType>
struct Constants;
template <>
struct Constants<1> {
static const int firstConst = 3;
static const int secondConst = 4;
};
template <>
struct Constants<2> {
static const int firstConst = 6;
static const int secondConst = -4;
};
template <int FuncType>
int foo(int x){
return Constants<FuncType>::firstConst + Constants<FuncType>::secondConst * x;
}
然后将其称为
foo<1>(42);
foo<2>(42);
答案 1 :(得分:3)
templatr<int funcType>
void foo(int x){
const int firstConst = (funcType==1) ? 3 : 6;
const int secondConst = (funcType==1) ? 4 : -4;
return firstConst+secondConst*x;
}
在任何非零优化设置下,没有值得使用的编译器将具有上述模板函数的运行时分支。
它比特质课更容易阅读。
通常,您可以使用此技术获得乐趣,编写可以编译为严格操作的长分支代码。如果您的代码很好地分解成片段(比如bool do_foo
作为模板参数),这可以很好地扩展。
超出此范围,您可能希望避免维护数字ID的中央列表。通过标签调度到constexpr ADL启用特征函数来查找特征,或者将一个模板非类型指针发送到constexpr结构,两者都可以通过分布式函数子类型声明为您带来零开销效果。
最后,你可以直接传递一个traits类:
template<class Traits>
void foo(int x){
return x*Traits::z+Traits::y;
}
或
template<class Traits>
void foo(int x){
return x*Traits{}.z+Traits{}.y;
}
甚至
template<class Traits>
void foo(int x, Traits traits={}){
return x*traits.z+traits.y;
}
取决于具体需求。
答案 2 :(得分:1)
与特质情况类似,你可以这样做:
template <int a, int b>
int foo(int x)
{
return a * x + b;
}
int foo1(int x){
return foo<4, 3>(x);
}
int foo2(int x){
return foo<-4, 6>(x);
}