7

クラスのテンプレート パラメータとして整数を使用しようとしています。コードのサンプルを次に示します。

template< int array_qty > 
class sample_class {

    public:
        std::array< std::string, array_qty > sample_array;

}

私がこのようなことをすると、うまくいきます:

sample_class< 10 > sample_class_instance;

ただし、コンパイル時に array_qty (テンプレート パラメーター) の値がわからず、実行時にしかわからないとしましょう。この場合、基本的にはテンプレート引数として int 変数を渡します。デモンストレーションのために、次のコードは機能しません。

int test_var = 2;
int another_test_var = 5;
int test_array_qty = test_var * another_test_var;

sample_class< test_array_qty > sample_class_instance;

上記を試すと、コンパイル時に次のエラーが発生します。

the value of ‘test_array_qty’ is not usable in a constant expression

テンプレートパラメーターとして渡すときに test_array_qty を const に変換しようとしましたが、それでもうまくいかないようです。これを行う方法はありますか、またはテンプレート パラメーターを誤用していますか? おそらく、それらはコンパイル時に認識される必要がありますか?

目標は、この特定のアプローチを解決することではなく、クラスをインスタンス化するときに指定できる int 変数に配列の長さを設定する方法を見つけることです。テンプレート パラメーターを介してこれを行う方法があれば、それが理想的です。

これには配列を使用する必要があり、最終的に提案になる可能性のあるベクトルではないことに注意してください。さらに、違いが生じる場合に備えて、array_qty は常に 0 から 50 の間の値になります。

4

5 に答える 5

10

これは効果的に行うことができます。しかし、あなたが間違った質問をしていると私が言うとき、私を信じてください. したがって、ほとんどの場合、それを行うのは悪い考えだと思っていても、次のことがあなたの質問に答えます。

実際にできることは、50 の異なるプログラムを、50 の可能なサイズごとに 1 つずつ作成し、条件付きで目的のプログラムにジャンプすることです。

template<int n>
struct prog {
  void run() {
    // ...
  }
};


template<int n>
struct switcher {
  void run(int v) {
    if(v==n)
      prog<n>::run();
    else
      switcher<n-1>::run(v);
  }
};

template<>
struct switcher<-1> {
  void run(int v){
  }
};

Call switcher<50>::run( value );and value が 0 から 50 の場合、prog<value>::run()呼び出されます。prog::runテンプレート パラメータ内には、コンパイル時の値があります。

恐ろしいハックです。別のソリューションを使用した方がよい可能性がありますが、それはあなたが求めていたものです。

C++14 テーブルベースのバージョンは次のとおりです。

template<size_t N>
using index_t = std::integral_constant<size_t, N>; // C++14

template<size_t M>
struct magic_switch_t {
  template<class F, class...Args>
  using R=std::result_of_t<F(index_t<0>, Args...)>;
  template<class F, class...Args>
  R<F, Args...> operator()(F&& f, size_t i, Args&&...args)const{
    if (i >= M)
      throw i; // make a better way to return an error
    return invoke(std::make_index_sequence<M>{}, std::forward<F>(f), i, std::forward<Args>(args)...);
  }
private:
  template<size_t...Is, class F, class...Args>
  R<F, Args...> invoke(std::index_sequence<Is...>, F&&f, size_t i, Args&&...args)const {
    using pF=decltype(std::addressof(f));
    using call_func = R<F, Args...>(*)(pF pf, Args&&...args);
    static const call_func table[M]={
      [](pF pf, Args&&...args)->R<F, Args...>{
        return std::forward<F>(*pf)(index_t<Is>{}, std::forward<Args>(args)...);
      }...
    };
    return table[i](std::addressof(f), std::forward<Args>(args)...);
  }
};

magic_switch_t<N>{}( f, 3, blah1, blah2, etc )を呼び出しf(index_t<3>{}, blah1, blah2, etc)ます。

一部の C++14 コンパイラは、ラムダを含む可変個パック展開でチョークします。必須ではありません。回避策を実行できますが、回避策は醜いです。

C++14 の機能はすべてオプションです。すべて C++11 で実装できますが、これも醜いです。

渡されるfものは基本的に関数オブジェクトでなければなりません (最初の引数として取るラムダauto、または手動のいずれか)。関数名を直接渡すのはうまくいきません。なぜなら、最初の引数がコンパイル時の値になるときに上記が最もうまくいくからです。

関数テンプレートをラムダまたは関数オブジェクトでラップすると、役立ちます。

于 2013-01-19T18:58:32.723 に答える
5

C++ 11 の場合、非型テンプレート引数は以下に制限されます (§14.3.2/1):

非型、非テンプレートのテンプレート パラメータのテンプレート引数は、次のいずれかになります。

  • 整数型または列挙型の非型テンプレート パラメーターの場合、テンプレート パラメーターの型の変換された定数式 (5.19)。また
  • 非型テンプレート パラメータの名前。また
  • 関数テンプレートと関数テンプレート ID を含むが非静的クラス メンバーを除く、静的ストレージ期間と外部または内部リンケージを持つオブジェクト、または外部または内部リンケージを持つ関数のアドレスを指定する定数式 (5.19)ただし、名前が関数または配列を参照する場合は & を省略でき、対応するテンプレート パラメーターが参照の場合は省略しなければなりません。また
  • null ポインター値に評価される定数式 (4.10)。また
  • null メンバ ポインタ値に評価される定数式 (4.11)。また
  • 5.3.1 で説明されているように表現されたメンバーへのポインター。

C++ 98 および 03 では、リストはさらに制限されています。結論: あなたがやろうとしていることは、単純に許可されていません。

于 2013-01-19T18:43:18.633 に答える
3

テンプレート引数は、コンパイル時の定数、別名「定数式」またはconstexpr略して s でなければなりません。したがって、テンプレートを使用する方法はありません。

動的サイズの配列を使用して、そのサイズをint.

または単にvector. ベクターのコンストラクターに目的のサイズを渡して、コンストラクターでそのサイズを必ず初期化してください。

于 2013-01-19T18:32:33.427 に答える
1

申し訳ありませんが、これは不可能です。テンプレート引数は、コンパイル時に既知の定数式でなければなりません。

于 2013-01-19T18:34:04.173 に答える