Porting C++ to C# - templates
I'm porting a C++ application to C#, and have run across templates. I've read up a little on these, and I understand that some templates are akin to .Net generics. I read the SO answer to this case which nicely summed it up.
However, some uses of c++ templating don't seem to be directly related to generics. In开发者_运维技巧 the below example from Wikipedia's Template metaprogramming article the template seems to accept a value, rather than a type. I'm not quite sure how this would be ported to 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
}
Clearly for this example I could do:
public int Factorial(int N){
if(N == 0) return 1;
return Factorial(N - 1);
}
but this seems to me to be a refactoring to a function, rather than a port to semantically similar code.
Unfortunately .Net generics can only accept types. C++ Templates take other values that are considered constant expressions by the compiler, because they are effectively just macros that expand to more code.
This means that your idea of turning the code into a method call is the best bet. You could make the method call return a type with a .Value Property (following your example) thus keeping the ported code similar to the template:
return Factorial(N-1).Value;
In the below example … the template seems to accept a value, rather than a type.
This isn’t your biggest problem. In fact, this could theoretically be solved in C# by using a Church numeral or Peano representation relying on nested generic types.1
However, your problem is that C# doesn’t allow template specialization. Template specialization is responsible in your example for defining that the factorial of 0
is 1
, rather than the same as for all other numbers. C# doesn’t allow doing that.
So there is no way to specify a base case in a recursive template (generic) definition and hence no recursion. C# generics aren’t Turing complete, whereas C++ templates are.
1 Something like this:
class Zero { }
class Successor<T> : Zero where T : Zero { }
// one:
Successor<Zero>
// two:
Successor<Successor<Zero>>
// etc.
Implementing operations on these numbers is left as an exercise to the reader.
Look at this article for the differences between C# generics and c++ templates:
I think your example is included there.
MSDN Link
The short answer is that, not everything that can be done in C++ templates can be done in C# generics. In the case of templates which accept non type values, each situation will have to be handled and re factored appropriately on a case by case basis.
This is as close as I could think of:
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)) );
}
}
The problem is you cannot define generics and limit it to ValueTypes
. This will work for byte, Int16 and Int32. Also for small values of Int64.
精彩评论