2011-01-15 28 views
26

C++で一般的な方法で何かを実装する方法がちょっと混乱しました。ちょっと複雑なので、私は一歩一歩説明しましょう。テンプレートの引数としてのテンプレート関数


は、このようなコードを考えてみましょう:

void a(int) { 
    // do something 
} 
void b(int) { 
    // something else 
} 


void function1() { 
    a(123); 
    a(456); 
} 
void function2() { 
    b(123); 
    b(456); 
} 

void test() { 
    function1(); 
    function2(); 
} 

それはそのfunction1顕著に容易だとfunction2は異なる部分のみが内部関数であることで、同じことを行います。

したがって、コードの冗長性を避けるため、functionを汎用化したいと考えています。私は関数ポインタやテンプレートを使ってそれを行うことができます。今私は後者を選んでみましょう。 私の考えは、コンパイラが確実に関数をインライン化することができるからです。正しいのですか?関数ポインタを使ってコンパイラがインラインで呼び出しを行うことはできますか?これは副疑問です。元のポイントに

OK、...テンプレートとソリューション:

void a(int) { 
    // do something 
} 
void b(int) { 
    // something else 
} 

template<void (*param)(int) > 
void function() { 
    param(123); 
    param(456); 
} 

void test() { 
    function<a>(); 
    function<b>(); 
} 

すべてOK。しかし、私は問題に遭遇しています:abがジェネリック自身であれば、それでもやってもいいですか?

template<typename T> 
void a(T t) { 
    // do something 
} 

template<typename T> 
void b(T t) { 
    // something else 
} 

template<...param...> // ??? 
void function() { 
    param<SomeType>(someobj); 
    param<AnotherType>(someotherobj); 
} 

void test() { 
    function<a>(); 
    function<b>(); 
} 

私は、テンプレートパラメータは、のいずれかであることを知っている:

  • タイプ、
  • テンプレートの種類、
  • 型の値。

私の状況をカバーするものはありません。私の主な質問は以下の通りです:最後の例でfunction()を定義するとどうすれば解決できますか?

(はい、この正確なケースでは、関数ポインタは回避策であるようですが、インライン化することもできますが、この問題の一般的な解決策を探しています)。

答えて

25

テンプレートでこの問題を解決するには、テンプレートテンプレートパラメータを使用する必要があります。 テンプレートテンプレート関数は、最初にインスタンス化する必要があるため、型として渡すことはできません。しかし、ダミー構造の回避策があります。次に例を示します。

template <typename T> 
struct a { 

    static void foo (T = T()) 
    { 
    } 

}; 

template <typename T> 
struct b { 

    static void foo (T = T()) 
    { 
    } 

}; 

struct SomeObj {}; 
struct SomeOtherObj {}; 

template <template <typename P> class T> 
void function() 
{ 
    T<SomeObj>::foo(); 
    T<SomeOtherObj>::foo(); 
} 

int main() 
{ 
    function<a>(); 
    function<b>(); 
} 
+0

これがなぜ落とされたのかは正確には分かりません。それは完全に満足できるものではありませんが、問題を解決します。 –

+0

要約:コールをインライン化することを可能にする唯一のソリューションは、関数をファンクタに置き換えることです。少し扱いに​​くいけど、まったく受け入れられると思う。ありがとう! – Kos

+1

しかし、私はあなたがバイ・アドレス呼び出しをインライン化することはできないと言った後、私は非常に驚いていると認めます...アドレスがコンパイル時に特定の関数のアドレスと等しいと判断できる場合、コンパイラは十分にスマートになる。 :)奇妙な... – Kos

0

これは方法です。それは最高ではないかもしれないが、それは動作します:

彼らはインライン化されますかどうかは
template <typename T, T param> 
void function() { 
    param(123); 
    param(456); 
} 

void test() 
{ 
    function< void(*)(int), a<int> >(); // space at end necessary to compiler 
    function< void(*)(int), b<int> >(); // because the C++ grammar is ambiguous 
} 

は、コンパイラに依存しますが、彼らがいなかった場合、私はかなり驚くだろう。

編集:さて、私は今日はちょっと離れており、パラメータが異なるタイプの部分を見逃しています。私の悪い。

は、テンプレートでこれを行うにはトリッキーな方法があるかもしれませんが、これは私が考える可能性が最も簡単な方法です:何とか何とか何とか、私は「マクロは悪です」、知っている

#define function(x) do { x<thing1>(obj1); x<thing2>(obj2) } while(0) 

私が知っています。できます。 functionがあなたの例よりも複雑である必要がある場合は、問題に遭遇するかもしれませんが、それは私が思い付くことができるものよりずっと簡単です。

+0

しかし 'function'は、パラメータテンプレート関数の異なるインスタンスを呼び出したいということに注意してください。 – Kos

+0

@Kos - '#define'は質問から外れていますか? –

+0

まあ、それはうまくいく "最後の手段"です:)しかし、編集、デバッグ、ネームスペースに入れることができないのは不愉快です...テンプレートベースのプリプロセッサベースのソリューションを見つけるのが好きです。 – Kos

-2
template < typename F > 
void function(F f) 
{ 
    f(123); 
} 

void a(int x) { ... } 

struct b { void operator() (int x) { ... } }; 

void outer() 
{ 
    function(&a); 
    function(b()); 
} 
+0

これはOPが望んでいたものではありません。 –

+1

ありがとうございますが、これは私が説明した問題とは無関係です。この場合、与えられた 'function'コールは、パラメータfunction/functorのインスタンス化を1つしか使用しません。質問をもう一度お読みください。 – Kos

関連する問題