我正在将C ++应用程序移植到C#,并且已跨模板运行。我已经阅读了一些这些,我知道有些模板类似于.Net泛型。我读了这个案例的SO answer,很好地总结了它。
然而,c ++模板的一些用法似乎与泛型没有直接关系。在以下维基百科的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);
}
但在我看来,这是对函数的重构,而不是语义相似代码的端口。
答案 0 :(得分:5)
不幸的是.Net泛型只能接受类型。 C ++模板采用编译器认为是常量表达式的其他值,因为它们实际上只是扩展为更多代码的宏。
这意味着您将代码转换为方法调用的想法是最好的选择。您可以使方法调用返回一个带有.Value属性的类型(按照您的示例),从而使移植的代码保持与模板类似:
return Factorial(N-1).Value;
答案 1 :(得分:5)
在下面的例子中......模板似乎接受一个值,而不是一个类型。
这不是你最大的问题。事实上,理论上可以通过使用依赖于嵌套泛型类型的Church numeral或Peano表示在C#中解决。 1
然而,您的问题是C#不允许模板专业化。模板专业化在您的示例中负责定义0
的阶乘为1
,而不是与所有其他数字相同。 C#不允许这样做。
因此无法在递归模板(通用)定义中指定基本案例,因此无法递归。 C#泛型不是图灵完整的,而C ++模板是。
1 这样的事情:
class Zero { }
class Successor<T> : Zero where T : Zero { }
// one:
Successor<Zero>
// two:
Successor<Successor<Zero>>
// etc.
对这些数字实施操作留给读者练习。
答案 2 :(得分:3)
答案 3 :(得分:1)
简短的回答是,并非C ++模板中可以完成的所有内容都可以在C#泛型中完成。对于接受非类型值的模板,必须根据具体情况适当处理和重新考虑每种情况。
答案 4 :(得分: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 的小值。