2

テンプレート仕様化のコードは次のとおりです。

template <int i>
struct userInput{};

template <>
struct userInput<1>
{
typedef int typeName;
};

template <>
struct userInput<2>
{
typedef double typeName;
};

そして、ユーザー入力に従って適切なテンプレートを選択したいと思います。

int i;
std::cin>>i;
userInput<i>::typeName ty;

しかし、コンパイラーは私に満足していません。テンプレートパラメーターに定数値を渡す必要があります。だから私はこれをしました:

int i;
std::cin>>i;    
const int p = i;
userInput<p>::typeName ty;

ただし、エラーがあります :template parameter 'i' : 'num' : ローカル変数を型以外の引数として使用することはできません。誰でも私を助けることができますか?私はそれを感謝します!

4

3 に答える 3

4

非型テンプレート パラメーターは、コンパイル時にインスタンス化されるため、定数のコンパイル時の式が必要です。

const int x = 1;
int y = 1;
userInput<x>::typeName a; // valid
userInput<1>::typeName a; // valid
userInput<y>::typeName b; // invalid, what should be instantiated?

p実行時に定数が初期化されるため、やりたいことを達成する方法はありません。

于 2012-06-26T23:43:29.520 に答える
3

switchテンプレートにフィードする定数値を見つけるには、入力が必要です。

template <int i>
void foo () {
    typename userInput<i>::typeName ty = 1;
    std::cout << ty/2 << std::endl;
}

int i;
std::cin >> i;
switch (i) {
case 1:  foo<1>(); break;
case 2:  foo<2>(); break;
default: std::cerr << "invalid type: " << i << std::endl;
}

したがって、入力が の場合1、出力は0です。入力が の場合2、出力は0.5です。それ以外の場合は、エラー メッセージが表示されます。

fooのコードと、作成しようとしたコードの違いは、foo<1>foo<2>が 2 つの異なる関数であり、それぞれに異なるty変数があり、各ty変数の型が異なることです。対照的に、コードには、シュレーディンガーの猫のように、同時にty両方の種類になろうとする単一の変数があります。typeNameコンパイラは波形を折りたたむことができなかったため、不平を言いました。

于 2012-06-27T00:40:08.257 に答える
1

mfontanini が説明しているように (そしてコンパイラが文句を言っています)、非型のテンプレート パラメータはコンパイル時の定数でなければなりません。そして、「const int p = i;」でだます試み 役に立ちません。p は定数変数かもしれませんが、コンパイル時の定数ではありません。C++11 コンパイラは、ここで何が問題なのかをより適切に伝えることができますが、問題を回避するのには役立ちません。実際、この問題を直接回避する方法はありません。

user315052 が示唆するように、最も簡単な解決策は明示的な切り替えです。そして、これを 1 回だけ実行し、1 対 2 のスイッチを入れるだけであれば、それ以上の労力を費やす価値はありません。

もちろん、スイッチを何度も実行している場合は、関数でラップするのは簡単です。

void bar(int i) {
  switch(i) {
  case 1: foo(userInput<1>::typeName()); return;
  case 2: foo(userInput<2>::typeName()); return;
  default: throw someException;
}

しかし、2 つ以上のケースがある場合、または一連の値が常に流動的である場合は、Boost.Preprocessor を使用してクラフトを自動化する必要があります。これは次のようになります。

#define FOO_CASES_ 50
#define FOO_PASTE_(rep, i, _) case i: foo(userInput< i >::typeName()); return;
void bar(int i) {
  switch (i) {
    BOOST_PP_REPEAT(FOO_CASES_, FOO_PASTE_, _)
    default: throw someException;
  }
}
#undef FOO_CASES_
#undef FOO_PASTE_

または、代わりに、コンパイルする .cpp ファイルを作成するコード ジェネレーターを記述します。

#!/usr/bin/env python
with file('bar.cpp', 'w') as f:
  f.write('void bar(int i) {\n')
  f.write('  switch(i) {\n')
  for i in range(50):
    f.write('    case %d: foo(userInput<%d>::typeName()); return;\n' % (i, i))
  f.write('  default: throw someException;\n')
  f.write('  }\n')
  f.write('}\n')

さらに別の方法は、適切なオブジェクト/関数などで初期化されたルックアップ配列 (またはベクトル) を作成することです。したがって、userInput の代わりに *userInputLookup[i] を使用できます。しかし、正確な使用例や、C++11 を使用しているかどうかを知らなければ、詳細を説明することは困難です。

于 2012-06-27T01:06:29.263 に答える