Why can't I create a template subclass of System :: Collections :: Generic :: IEnumerable <T>?
I want to create a general IEnumerable implementation to make it easier to port some of the native C ++ classes. When I try to create an implementation using the template parameter as the IEnumerable parameter, 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>(); } In the specified line, I get this error:
error C3225: the universal type argument for "T" cannot be "B ^", it must be a value type or a handle of a reference type
If I use another parent class, I do not see a 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 get around this 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 it seems dirty to me. Also, I just wanted to understand what is going on here - why does the first method not work?
In the first example, your inheritance line should look like this:
ref class Test : public System::Collections::Generic::IEnumerable<B> (no reference marker in the template)
Then your usage string should look like this:
Test<A^> ^a = gcnew Test<A^>(); Control markers are part of the template instance, not the template itself.
Here is your sample that can be compiled:
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: Implemented I have to explain why this is. As far as I understand, the reason why you cannot specify B ^ in inheritance of IEnumerable is that IEnumerable is common with a restriction on it, and B is a template parameter that has no restrictions. Templates allow you to use much more flexible syntax, even when they manipulate ref objects, since they still effectively βparse textβ even in C ++ / CLI. However, when faced with generic restrictions, the rules become much more stringent.