【问题标题】:Why can't I create a templated subclass of System::Collections::Generic::IEnumerable<T>?为什么我不能创建 System::Collections::Generic::IEnumerable<T> 的模板化子类?
【发布时间】:2010-04-02 19:11:06
【问题描述】:

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

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

【问题讨论】:

    标签: templates generics c++-cli


    【解决方案1】:

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

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

    【讨论】:

    • 谢谢,这解决了最初的问题。不过,我留下了部分问题——我还想在 Test 类中创建 B 的新实例。使用您的解决方案, gcnew B() 失败,因为 B 是句柄类型,有没有办法解决这个问题?
    • 是的,虽然它一点也不直观。使用Activator::CreateInstance&lt;T&gt;()。我更新了上面的示例来演示。
    猜你喜欢
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-27
    • 2020-05-26
    • 2011-04-04
    相关资源
    最近更新 更多