C ++ / CLI: бокс и общие списки - PullRequest
2 голосов
/ 13 октября 2009

Я пытаюсь создать общий список ссылок на PointF объекты. (Нет, я не собираюсь создавать общий список PointF объектов.) Однако следующая строка не компилируется:

Generic::List<PointF^> ^pointList; // Generates error C3225

С другой стороны, создание массива ссылок PointF работает без проблем следующим образом:

array<PointF^> ^points = gcnew array<PointF^>;

Вот пример программы:

using namespace System;
using namespace System::Drawing;
namespace Generic = System::Collections::Generic;

int main(array<System::String ^> ^args)
{

    array<PointF^> ^points = gcnew array<PointF^>{
        nullptr, PointF(0.0f, 0.0f), PointF(1.0f, 0.0f), nullptr
    };

    Generic::List<PointF^> ^pointList;
    Console::WriteLine(L"Hello World");
    return 0;
}

Как мне создать общий список PointF ссылок? Другими словами, как мне создать общий список в штучной упаковке PointF с?

Ответы [ 4 ]

4 голосов
/ 24 октября 2009

Это предел универсального .Net, который принимает только CLI-совместимый тип, такой как тип значения или ссылку на ссылочный тип. Он не принимает специфичные для C ++ / CLI типы, такие как семантика стека для типов ref (что компилируется в детерминированную финализацию) или, в вашем случае, ссылку на тип значения в штучной упаковке.

Массив является родным для CLI и не имеет этого ограничения.

0 голосов
/ 02 июня 2015

Как уже упоминалось, универсальные типы принимают только CLS-совместимые параметры типов.Поскольку PointF^ не является CLS-совместимым, List<PointF^> недопустимо.array<> позволяет избежать этой проблемы, поскольку является типом шаблона, а не универсальным типом.

Однако, есть (довольно легкий) обходной путь: создайте List<Nullable<PointF>>.Ваша примерная программа становится:

using namespace System;
using namespace System::Drawing;
namespace Generic = System::Collections::Generic;

int main(array<System::String ^> ^args)
{

    array<Nullable<PointF>> ^points = gcnew array<Nullable<PointF>> {
        Nullable<PointF>(), Nullable<PointF>(PointF(0.0f, 0.0f)), Nullable<PointF>(PointF(1.0f, 0.0f)), Nullable<PointF>()
    };

    Generic::List<Nullable<PointF>> pointList(points);
    pointList.Add(PointF(2., 0.));
    Console::WriteLine(L"Hello World");
    return 0;
}
0 голосов
/ 06 февраля 2013

Несмотря на то, что хранилище типа PointF и объект кучи, на которые ссылается PointF^, являются разными видами вещей, они оба описываются одним и тем же объектом Type. Система обычно решает, что именно представляет Type, основываясь на том, как используется тип. Если тип PointF используется для описания места хранения, то это место хранения будет выделено для хранения структуры. Компилятор C ++ / CLI может разрешить объявление переменной PointF^, но в Framework нет такой концепции. В коде C ++ / CLI компилятор может использовать место хранения типа Object для хранения ссылки на объект кучи PointF, или он может использовать Object[] для хранения группы таких ссылок; если такие местоположения никогда не открываются внешнему миру, и компилятор никогда не хранит ничего, кроме ссылок PointF, компилятор может знать, что цель любой ненулевой ссылки может безопасно использоваться как PointF. Однако компилятор не может предоставить такие места хранения внешнему коду, потому что система типов не предоставляет средств для указания того, что другой код должен ограничиваться хранением PointF ссылок.

0 голосов
/ 13 октября 2009

PointF это не класс, это структура. Вы не можете иметь ссылки на структуру, не помещая ее внутрь объекта.

Вы можете иметь список Object ссылок и распаковывать ссылку на PointF всякий раз, когда вы его используете, или список пользовательских классов, инкапсулирующих значение PointF.

С неявными преобразованиями в и из значения PointF вы можете сделать прозрачными упаковку и распаковку. Я не уверен, как вы пишете это в C ++, но в C # это будет выглядеть так:

public class PointFObject {

   // encapsulated PointF structure
   private PointF _value;

   // constructor
   public PointFObject(PointF value) {
      _value = value;
   }

   // implicit conversion to a PointF value
   public static implicit operator PointF(PointFObject obj) {
      return obj._value;
   }

   // implicit conversion from a PointF value
   public static implicit operator PointFObject(PointF value) {
      return new PointFObject(value);
   }

}

Теперь вы можете создать список PointFObject и обращаться к ним как к списку значений PointF:

List<PointFObject> pointList = new List<PointFObject>();
pointList.Add(new PointF(0f, 0f));
PointF p = pointList[0];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...