5

私は持っています

template <int i> struct a { static void f (); };

コード内のさまざまな場所で特殊化が行われます。実行時にのみ既知の正しいものa<i>::fを呼び出すにはどうすればよいですか?i

void f (int i) { a<i>::f (); } // won't compile

iの可能なすべての値を大きな値でリストしたくありませんswitch

編集:

私は次のようなことを考えました

#include <iostream>

template <int i> struct a { static void f (); };

struct regf {
  typedef void (*F)();
  enum { arrsize = 10 };
  static F v[arrsize];
  template < int i > static int apply (F f) {
    static_assert (i < arrsize, "");
    v[i] = a<i>::f;
    return 0;
  }
};
regf::F regf::v[arrsize];

template <int i> struct reg { static int dummy; };
template <int i> int reg<i>::dummy = regf::apply<i> ();

void f (int i) { return regf::v[i] (); }

#define add(i) \
  template <> struct a<i> : reg<i> { \
    static void f () { std::cout << i << "\n"; } \
  };

add(1)
add(3)
add(5)
add(7)

int main () {
  f (3);
  f (5);
}

しかし、それはクラッシュし(インスタンス化を強制するために何かを逃したのですか?)、ダミーがそうではないstatic const(そしてメモリを使用する)ことは好きではありません。もちろん、それarrsizeは必要以上に大きいです。


実際の問題:実行時にのみ指定されたクラスのインスタンスを生成するためgenerate (int i)に呼び出す関数を持つこと。デザイン(クラス)が与えられ、それらは基本クラスから継承され、コードのどこにでもいつでもより多くの特殊化を追加できますが、それは簡単に忘れられる可能性があるため、すべての人に手動で変更するように強制したくありません。a<i>::generate ()a<i>ia<i>generate (i)

4

5 に答える 5

5

より良い設計があるかもしれないので、これがあなたが得ることができる最良の解決策であるかどうかはわかりませんが、とにかくメタプログラミングを使用して関数のインスタンス化とレジストリをトリガーできます:

// in a single cpp file
namespace {
template <unsigned int N>
int register_a() {         // return artificially added
   register_a<N-1>();      // Initialize array from 0 to N-1
   regf::v[N] = &a<N>::f;  // and then N
   return N;
}
template <>
int register_a<0>() {
   regf::v[0] = &a<0>::f;  // recursion stop condition
   return 0;
}
const int ignored = register_a<regf::arrsize>(); // call it
}

そのコードは関数をインスタンス化し、静的メンバー関数へのポインターを登録します。偽の戻り型は、静的コンテキストで関数を強制的に実行できるようにするために必要です(静的値を初期化するためにその関数を使用することによって)。

これは、静的初期化の大失敗を非常に起こしやすいです。大丈夫ですが、静的初期化中に適切なポインタを含めるregf::vことに依存するコードは必ず失敗します。regf::vあなたは通常のテクニックでこれを改善することができます...

あなたが実際に投稿した断片から、あなたは具体的な各工場からの自動登録を備えた抽象的なファクトリを使用しようとしていると思います。問題に取り組むためのより良い方法がありますが、この答えはあなたの質問を解決すると思います(これがあなたの問題を解決するかどうかはわかりません)。

于 2011-04-11T15:55:17.607 に答える
4

必ず。テンプレートはコンパイル時に解決され、インスタンス化されます。それとは別に、switch非効率である必要はありません。通常、オーバーヘッドがほとんどないルックアップテーブルにコンパイルされます。

ただし、再帰的なテンプレートマジックを使用して、コンパイラによって生成されたif/elseものを置き換えるためにネストされたブロックを作成することができます。switchしかし、プレーンswitchははるかに読みやすいはずです。もちろん、文字通り何千ものケースがない限り。

いずれの場合もi、コンパイラーはインスタンス化するテンプレートを知る必要があるため、コンパイル時に持つことができる値のセットを知る必要があります。

于 2011-04-11T13:12:08.917 に答える
2

実行時にテンプレートの特殊化を選択することはできません。それらは、定義上、コンパイル時に選択されます。

あなたが見ているディスパッチ問題を解決する通常の方法は、switch(あなたが推測したように)またはvectorまたはmapint関数ポインタです。

于 2011-04-11T14:04:46.643 に答える
1

いいえ、コンパイラはコンパイル時にテンプレートをインスタンス化する必要があります。そのため、コンパイラはコンパイル時にの値を知る必要がありますi

于 2011-04-11T13:13:26.623 に答える
1

テンプレートのインスタンス化はコンパイル時に行われるため、できません。

于 2011-04-11T13:34:25.857 に答える