将C ++移植到C# - 模板

时间:2011-01-19 13:34:20

标签: c# .net c++ templates porting

我正在将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);
}

但在我看来,这是对函数的重构,而不是语义相似代码的端口。

5 个答案:

答案 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)

请看这篇文章,了解C#generics和c ++模板之间的区别:

我认为你的例子包含在那里。

MSDN Link

答案 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 的小值。