2017-10-11 16 views
3

私は、引数に対して全く同じ操作を実行するが、そうするために異なるセットの定数を使う2つの関数を持っているとしましょう。単純化しすぎたとえば:実際のアプリケーションで類似の関数を避けるためのテンプレートの使用

int foo1(int x){ 
    return 3+4*x 
} 
int foo2(int x){ 
    return 6-4*x 
} 

複数の引数と定数/リテラル​​、そしてもちろん計算がはるかに複雑になりますがあるだろうと仮定します。 簡潔さと保守性のために、私はfoo < 1>またはfoo < 2>を呼び出すことができるように、これら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
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が有効なtraits関数にタグをディスパッチすることで特性を見つけたり、constexpr構造体へのテンプレートの非型ポインタを指定したりすることで、分散関数のサブタイプ宣言でゼロオーバーヘッド効果が得られます。

最後に、あなただけの直接に特性クラスを渡すことができます。特定のニーズに応じて、

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; 
} 

を。特徴のケースに、あなたが行うことができます。同様

+0

両方の答えは正しかったと、他の一つは動作するはずかかわらず、コンパイラ設定のが、この方法では、間違いなく読みやすいです。 – chessprogrammer

+1

しかし、これはより多くの機能にうまく対応しません。私たちが保守性について話しているので、私はなぜこれがsongyuanyaoの答え(https://stackoverflow.com/a/46679563/4832499)のほうが好まれないのか分かりません。 –

+0

@passer当然。Amdではなくても、constexpr構造体へのテンプレートポインターや、ADLタグディスパッチされたtraits関数は、IDを維持するだけであっても、 "call function '253'よりもスケーラビリティの高い関数を見つけることができます。 – Yakk

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

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); 
} 
+0

これは、多数の定数ではスケールがうまくいかないが、例のような小さな関数の方が簡単になる – chessprogrammer

関連する問題