我想创建一个通用的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^>>();
}
但这对我来说似乎很混乱。另外,我只想了解这里发生了什么 - 为什么第一种方式不起作用?
答案 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中它们仍然是有效的“解析文本”。然而,当他们遇到有限制的泛型时,规则会变得更加严格。