2011-01-19 31 views
5

私はC++アプリケーションをC#に移植し、テンプレート間で実行しています。私はこれらを少し読んで、いくつかのテンプレートは.Netジェネリックに似ていることを理解しています。私はSO answerをよく読んだこのケースに読んだ。C++からC#への移植 - テンプレート

しかし、C++テンプレートのいくつかの使用法はジェネリックに直接関係していないようです。下の例では、WikipediaのTemplate metaprogrammingの記事から、テンプレートは型ではなく値を受け入れるようです。私はこれがどのようにC#に移植されるのかははっきりしていませんか?

template <int N> 
struct Factorial 
{ 
    enum { value = N * Factorial<N - 1>::value }; 
}; 

template <> 
struct Factorial<0> 
{ 
    enum { value = 1 }; 
}; 

// Factorial<4>::value == 24 
// Factorial<0>::value == 1 
void foo() 
{ 
    int x = Factorial<4>::value; // == 24 
    int y = Factorial<0>::value; // == 1 
} 

は明らかに、この例のために私は何ができる:

public int Factorial(int N){ 
    if(N == 0) return 1; 
    return Factorial(N - 1); 
} 

が、これは関数のリファクタリングではなく、意味的に類似したコードへのポートであることを私には思えます。私はあなたの例がそこに含まれていると思います

:C#のジェネリックとC++テンプレートの違いについては、この記事で

+0

なぜ古典的な再帰関数をC#genericsとして使用しますか?この記事を読むhttp://msdn.microsoft.com/en-us/library/bb549151.aspx Funcの使用について nemke

+1

問題は、テンプレートのパラメータとして定数(対型)を使用している可能性はほとんどありませんが、現在のコードベースで使用されている場合は、クラスまたは関数の特殊化と部分的な特殊化が含まれます。特定の例がなければ、答えは幅広く、おそらく本当に有用ではないでしょう。私はその理由でクローズすることに投票しています。あなたが変換に問題があるコードのいくつかについて特別な質問を自由に追加してください。 –

+1

@nemke - この例では、Factorialテンプレートはコンパイル時に展開されるため、実行時に実際には何も行われません。 OPは、多すぎる種類のC#呼び出しに翻訳する必要なしにコードを移植したいので、できるだけジェネリックベースのソリューションが好まれます。残念ながら、そうではありません。 @David - 非常に良い点 –

答えて

5

あいにくの.NETジェネリック型のみを受け入れることができます。 C++テンプレートは、より多くのコードに展開されるマクロであるため、コンパイラによって定数式と見なされる他の値をとります。

これは、コードをメソッド呼び出しに変えるというあなたの考えが最善の策であることを意味します。あなたは、このように、テンプレートに似た移植されたコードを維持するメソッド呼び出しは、(あなたの例以下).Valueのプロパティを持つ型を返す作ることができます:

return Factorial(N-1).Value; 
+0

C#とC++コンパイラは基本的に異なりますが、C#チームはコンパイル時(マクロとテンプレート)でコードを書く機能を備えていますが、C#チームは意図的にこれを避けていました。 C#はそれに近づくかもしれませんが、決して同じではありません。 –

+0

+1 C#のジェネリックスは便利ですが、MSDNのリンクによれば、すべてが動的に実行されるため、コンパイル時の型チェック(コンパイル時の型チェック)ではなく、コンパイル時の計算あなたがしている例)。 – MatiasFG

+0

@MatiasFG - ポイントジェネリックは正確に動的にコンパイルされますが、コードの型チェックはジェネリック型のコンパイル時に行われます。私はC#のテンプレートメタ機能を始めたC++のテンプレート機能を持っていないのは間違いですが、C#開発者になる前に直ちに - しかし、ジェネリックは非常に非常に涼しく、私たちはそれらを持っていることを嬉しく思っています! –

3

ルック。

MSDN Link

+0

ありがとう、このケースを除外しません: "C#はテンプレートC以外 {}"のような型のないテンプレートパラメータを許可しません。上記の質問で行ったように、これらの種類のテンプレートを移植する最善の方法は、リファクタリングですか? –

+1

上記の状況では、メソッドへのリファクタリングがおそらく最善の方法です。しかし、それぞれの状況はケースバイケースで処理する必要があります。場合によっては、クラスのコンストラクタに値を提供することが必要な場合があります。 –

+1

良いことは、C#ではC++のようなコンパイル時定数を必要としないことです。たとえば、配列を宣言するときには、ほとんどの場合、実行時の計算によって期待される結果が得られます。 –

1

短い答えはCで行うことができますすべてではない、ということです++テンプレートはC#のジェネリックで行うことができます。非型の値を受け入れるテンプレートの場合、それぞれの状況を処理しなければならず、ケースバイケースで適切に因数分解する必要があります。

0

これは私が考える可能性が限り近い:

public class Factorial<T> 
    where T : IConvertible 
    { 
     public T GetFactorial(T t) 
     { 
      int int32 = Convert.ToInt32(t); 
      if (int32 == 0) 
       return (T) Convert.ChangeType(1, typeof(T)); 
      return GetFactorial((T) Convert.ChangeType(int32-1, typeof(T))); 
     } 
    } 

問題は、あなたがジェネリックを定義し、ValueTypesにそれを制限することはできませんです。これはバイト、Int16およびInt32で動作します。 Int64の小さな値についても。

+0

明確にするため、問題は数値に制限できないことです。あなたはstructとIComparableのためにそこにいくつかの制約を置くことができますが、数値/非数値を決定するのはそれほど難しくありません。 –

5

以下の例では、テンプレートはタイプではなく値を受け入れているようです。

これはあなたの最大の問題ではありません。実際には、これは理論的にはC#でChurch numeralまたは入れ子のジェネリック型に依存するPeano表現を使用して解決することができます。

しかし、あなたの問題は、C#はテンプレートの特殊を許可していないということです。あなたの例では、他のすべての数と同じではなく、0の階乗が1であることを定義するのは、テンプレートの特殊化です。 C#はそれを許可していません。

したがって、再帰的テンプレート(総称)定義で基本ケースを指定する方法はなく、したがって再帰はありません。 C#のジェネリックは完全なチューリングではなく、C++のテンプレートは完全なものです。


このような何か:

class Zero { } 

class Successor<T> : Zero where T : Zero { } 

// one: 
Successor<Zero> 
// two: 
Successor<Successor<Zero>> 
// etc. 

は、これらの数字の操作を実装するには、読者への課題として残されています。

関連する問題