views:

473

answers:

1

Hi. I'm writing a generics class in C++/CLI (VS2008) to store and manage records of different kinds and I need collections to keep them before flusing them to DB/disk/etc. I was thinking in something like this:

ref class Record
{
    // ...
};

generic<typename T>
where T : Record, gcnew()
public ref class Factory
{
public:
    // ....functions....
protected:
    array<T^> ^    StoredData;
};

Which of course failed with error C3229 (indirections on a generic type parameter are not allowed). If I remove the '^', the error is then C3149 (cannot use this type here without a top-level '^'). This is easily done in VB.Net (in fact, I'm migrating an existing VB.Net class!), but in C++ I seem to have reached a dead end. Is this actually impossible in C++/CLI?

Thanks in advance.

+2  A: 

What you need to do is this:

public ref class Record
{
};

generic<typename T>
where T : Record, gcnew()
public ref class Factory
{
public:
    // ....functions....
protected:
    array<T> ^    StoredData;
};

You then instantiate the collection like so:

Factory<Record^>^ records = gcnew Factory<Record^>();

This is what MSDN has to say about generics in C++:

Both value types (either built-in types such as int or double, or user-defined value types) and reference types may be used as a generic type argument. The syntax within the generic definition is the same regardless. Syntactically, the unknown type is treated as if it were a reference type. However, the runtime is able to determine that if the type actually used is a value type and substitute the appropriate generated code for direct access to members. Value types used as generic type arguments are not boxed and so do not suffer the performance penalty associated with boxing. The syntax used within the body of the generic should be T^ and '->' instead of '.'. Any use of gcnew for the type parameter will be appropriately interpreted by the runtime as the simple creation of a value type if the type argument is a value type.

So this means, I think, that any generic type argument is treated as a pointer to managed class i.e. T^. In fact you cannot instantiate a generic class using something like this:

Factory<Record>^ records = gcnew Factory<Record>();

The compiler will throw this error(even if you remove where T : Record, gcnew()):

error C3225: generic type argument for 'T' cannot be 'Record', it must be a value type or a handle to a reference type
Igor Zevaka
You are so right. I could swear I tried that, but obviously I did not. :) It works perfectly, thank you.
Guillermo Prandi