为什么我不能创建 System::Collections::Generic::IEnumerable的模板化子类?

发布于 2024-08-28 01:32:06 字数 1094 浏览 8 评论 0原文

我想创建一个通用的 IEnumerable 实现,以便更轻松地包装一些本机 C++ 类。当我尝试使用模板参数作为 IEnumerable 的参数来创建实现时,出现错误。

这是我想出的一个简单版本,它演示了我的问题:

ref class A {};

template<class B>
ref class Test : public System::Collections::Generic::IEnumerable<B^> // error C3225...
{};

void test()
{
    Test<A> ^a = gcnew Test<A>();
}

在指定的行上,我收到此错误:

错误 C3225:“T”的泛型类型参数不能是“B ^”,它必须是值类型或引用类型的句柄

如果我使用不同的父类,我看不到问题:

template<class P>
ref class Parent {};

ref class A {};

template<class B>
ref class Test : public Parent<B^> // no problem here
{};

void test()
{
    Test<A> ^a = gcnew Test<A>();
}

我可以解决此问题通过向实现类型添加另一个模板参数来实现:

ref class A {};

template<class B, class Enumerable>
ref class Test : public Enumerable
{};

void test()
{
    using namespace System::Collections::Generic;
    Test<A, IEnumerable<A^>> ^a = gcnew Test<A, IEnumerable<A^>>();
}

但这对我来说似乎很混乱。另外,我只是想了解这里发生了什么 - 为什么第一种方法不起作用?

I want to create a generic IEnumerable implementation, to make it easier to wrap some native C++ classes. When I try to create the implementation using a template parameter as the parameter to IEnumerable, I get an error.

Here's a simple version of what I came up with that demonstrates my problem:

ref class A {};

template<class B>
ref class Test : public System::Collections::Generic::IEnumerable<B^> // error C3225...
{};

void test()
{
    Test<A> ^a = gcnew Test<A>();
}

On the indicated line, I get this error:

error C3225: generic type argument for 'T' cannot be 'B ^', it must be a value type or a handle to a reference type

If I use a different parent class, I don't see the problem:

template<class P>
ref class Parent {};

ref class A {};

template<class B>
ref class Test : public Parent<B^> // no problem here
{};

void test()
{
    Test<A> ^a = gcnew Test<A>();
}

I can work around it by adding another template parameter to the implementation type:

ref class A {};

template<class B, class Enumerable>
ref class Test : public Enumerable
{};

void test()
{
    using namespace System::Collections::Generic;
    Test<A, IEnumerable<A^>> ^a = gcnew Test<A, IEnumerable<A^>>();
}

But this seems messy to me. Also, I'd just like to understand what's going on here - why doesn't the first way work?

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

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

发布评论

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

评论(1

入画浅相思 2024-09-04 01:32:06

在您的第一个示例中,您的继承行应为:(

ref class Test : public System::Collections::Generic::IEnumerable<B>

模板上没有引用标记)

然后您的使用行应为:

Test<A^> ^a = gcnew Test<A^>();

引用标记位于模板的实例化中,而不是模板本身。

这是您的示例,可编译:

using namespace System;
using namespace System::Collections::Generic;

ref class A {};

template<class B> ref class Test : public System::Collections::Generic::IEnumerable<B>
{
public:
    B GetInstance()
    {
        return Activator::CreateInstance<B>();
    }

    virtual System::Collections::IEnumerator^ GetEnumeratorObj() =
        System::Collections::IEnumerable::GetEnumerator
    {
        return nullptr;
    }

    virtual System::Collections::Generic::IEnumerator<B>^ GetEnumerator()
    {
        return nullptr;
    }
};

void test()
{
    Test<A^> ^a = gcnew Test<A^>();
}

编辑:意识到我应该解释为什么会这样。据我所知,不能在 IEnumerable 继承中指定 B^ 的原因是 IEnumerable 是一个带有约束的泛型,而 B 是一个不受约束的模板参数。模板允许更灵活的语法,即使它们管理 ref 对象,因为即使在 C++/CLI 中,它们仍然是有效的“解析文本”。然而,当他们遇到有约束的泛型时,规则就会变得更加严格。

In your first example, your inheritance line should read:

ref class Test : public System::Collections::Generic::IEnumerable<B>

(no reference marker on the template)

Then your usage line should read:

Test<A^> ^a = gcnew Test<A^>();

The reference markers go in the instantiation of the template, not the template itself.

Here's your sample, compilable:

using namespace System;
using namespace System::Collections::Generic;

ref class A {};

template<class B> ref class Test : public System::Collections::Generic::IEnumerable<B>
{
public:
    B GetInstance()
    {
        return Activator::CreateInstance<B>();
    }

    virtual System::Collections::IEnumerator^ GetEnumeratorObj() =
        System::Collections::IEnumerable::GetEnumerator
    {
        return nullptr;
    }

    virtual System::Collections::Generic::IEnumerator<B>^ GetEnumerator()
    {
        return nullptr;
    }
};

void test()
{
    Test<A^> ^a = gcnew Test<A^>();
}

Edit: Realized I should explain why this is. To the best of my understanding, the reason that you can't specify B^ in the IEnumerable inheritance is that IEnumerable is a generic with a constraint on it, while B is a template parameter which is unconstrained. Templates allow for much more flexible syntax, even when they govern ref objects, as they're still effectively "parsed text" even in C++/CLI. However, when they bump into generics with constraints, the rules get a lot tighter.

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