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?
In your first example, your inheritance line should read:
(no reference marker on the template)
Then your usage line should read:
The reference markers go in the instantiation of the template, not the template itself.
Here’s your sample, compilable:
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.