移植 C++到 C# - 模板

发布于 2024-10-12 18:24:20 字数 982 浏览 3 评论 0原文

我正在将 C++ 应用程序移植到 C#,并跨模板运行。我已经阅读了一些关于这些的内容,并且我知道一些模板类似于 .Net 泛型。我读了 SO回答 这个案例很好地总结了这一点。

然而,C++ 模板的某些用途似乎与泛型没有直接关系。在下面来自 Wikipedia 的 模板元编程 文章的示例中,模板似乎接受一个值,而不是一个类型。我不太确定如何将其移植到 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);
}

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

从﹋此江山别 2024-10-19 18:24:20

不幸的是.Net 泛型只能接受类型。 C++ 模板采用编译器视为常量表达式的其他值,因为它们实际上只是扩展为更多代码的宏。

这意味着将代码转换为方法调用的想法是最好的选择。您可以使方法调用返回带有 .Value 属性的类型(按照您的示例),从而使移植的代码与模板相似:

return Factorial(N-1).Value;

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;
临走之时 2024-10-19 18:24:20

在下面的示例中......模板似乎接受一个值,而不是一个类型。

这不是你最大的问题。事实上,理论上这个问题可以在 C# 中通过使用 Church numeric 或依赖于嵌套的 Peano 表示来解决泛型类型。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.

对这些数字实施操作留给读者作为练习。

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.

趴在窗边数星星i 2024-10-19 18:24:20

简而言之,并不是 C++ 模板中可以完成的所有操作都可以在 C# 泛型中完成。对于接受非类型值的模板,必须根据具体情况适当处理和重构每种情况。

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.

债姬 2024-10-19 18:24:20

这与我能想到的最接近:

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文