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

时间:2010-04-02 19:11:06

标签: templates generics c++-cli

我想创建一个通用的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^>>();
}

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

1 个答案:

答案 0 :(得分:3)

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

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中它们仍然是有效的“解析文本”。然而,当他们遇到有限制的泛型时,规则会变得更加严格。