使用模板来避免类似的功能

时间:2017-10-11 03:49:29

标签: c++ templates code-maintainability

假设我有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;
}

但是因为我总是在编译时知道我想要使用哪个函数,所以我想使用模板来避免分支。有没有办法做到这一点?

3 个答案:

答案 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);
}