Обобщения C ++ / CLI, использование T в массиве <> и других коллекциях - PullRequest
2 голосов
/ 07 декабря 2009

Я пишу универсальный класс в C ++ / CLI (VS2008) для хранения и управления записями разных видов, и мне нужны коллекции, чтобы хранить их, прежде чем записывать их в БД / диск / и т. Я думал примерно так:

ref class Record
{
    // ...
};

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

Что, конечно, не удалось с ошибкой C3229 ( не допускаются косвенные ссылки на параметр универсального типа ). Если я удалю '^', ошибка будет C3149 ( не может использовать этот тип здесь без верхнего уровня '^' ). Это легко сделать в VB.Net (на самом деле я переношу существующий класс VB.Net!), Но в C ++ я, кажется, зашел в тупик. Это на самом деле невозможно в C ++ / CLI?

Заранее спасибо.

1 Ответ

6 голосов
/ 07 декабря 2009

Что вам нужно сделать, это:

public ref class Record
{
};

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

Затем вы создаете экземпляр коллекции следующим образом:

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

Вот что говорит MSDN о дженериках в C ++:

Оба типа значений (встроенные типы, такие как int или double, или определяемые пользователем типы значений) и ссылочные типы могут использоваться в качестве аргумента универсального типа. Синтаксис в общем определении одинаков независимо. Синтаксически, неизвестный тип обрабатывается так, как если бы он был ссылочным типом. Однако среда выполнения может определить, является ли фактически используемый тип типом значения, и заменить соответствующий сгенерированный код для прямого доступа к членам. Типы значений, используемые в качестве аргументов универсального типа, не упакованы и поэтому не страдают от снижения производительности, связанного с упаковкой. Синтаксис, используемый в теле универсального шаблона, должен быть T ^ и '->' вместо '.'. Любое использование gcnew для параметра типа будет соответствующим образом интерпретироваться средой выполнения как простое создание типа значения, если аргумент типа является типом значения.

Так что, я думаю, это означает, что любой аргумент универсального типа обрабатывается как указатель на управляемый класс, т. Е. T ^. На самом деле вы не можете создать экземпляр универсального класса, используя что-то вроде этого:

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

Компилятор выдаст эту ошибку (даже если вы удалите 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
...