Generics из FCL-STL

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Generics из FCL-STL

Сообщение woodhead » 24.07.2018 11:32:38

Здравствуйте.
Подскажите, пожалуйста, как правильно использовать обобщённые классы из библиотеки FCL-STL.
Например, почему в таком коде ошибка "Error: Identifier not found "TSet$1"":
Код: Выделить всё
interface

uses
  Classes, SysUtils, GSet;

type
   TMyClass = class(TObject)
     fld1 : string;
   end;

   TMyList = specialize TSet<TMyClass>;

woodhead
новенький
 
Сообщения: 21
Зарегистрирован: 24.12.2014 12:23:20

Re: Generics из FCL-STL

Сообщение Ichthyander » 24.07.2018 11:56:26

TMyList = specialize TSet<TMyClass>;
А где второй класс внутри <>?

Добавлено спустя 1 минуту 2 секунды:
Определение TSet
Код: Выделить всё
  generic TSet<T, TCompare>=class
  public
  type
    PNode=^Node;
    Node=record
      Data:T;
      Left,Right:PNode;
      Parent:PNode;
      Color:boolean;
    end;   
... ... ... ...


Добавлено спустя 1 минуту 12 секунд:
Пример использования в исходниках FCL-STL, модуль setexample
Код: Выделить всё
uses gset, gutil;

type lesslli=specialize TLess<longint>;
     setlli=specialize TSet<longint, lesslli>;

var data:setlli; i:longint; iterator:setlli.TIterator;

begin
  data:=setlli.Create;

  for i:=0 to 10 do
    data.insert(i);

  {Iteration through elements}
  iterator:=data.Min;
  repeat
    writeln(iterator.Data);
  until not iterator.next;
  {Don't forget to destroy iterator}
  iterator.Destroy;

  iterator := data.FindLess(7);
  writeln(iterator.Data);
  iterator.Destroy;

  data.Destroy;
end.
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 668
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

Re: Generics из FCL-STL

Сообщение woodhead » 24.07.2018 16:09:19

Попробовал сделать по примеру, все равно не получается.
Вот код:
Код: Выделить всё
interface
uses
  Classes, SysUtils, gset, gutil;

type
   TMyClass = class(TObject)
     fld1 : string;
   end;

  lesslli=specialize TLess<TMyClass>;
  TMyList = specialize TSet<TMyClass, lesslli>;

Выдаёт ошибку:
Error: Operator is not overloaded: "TMyClass" < "TMyClass"
woodhead
новенький
 
Сообщения: 21
Зарегистрирован: 24.12.2014 12:23:20

Re: Generics из FCL-STL

Сообщение Ichthyander » 24.07.2018 16:39:38

Вы попробуйте разобраться как код работает. Посмотрите, что за класс TLess в модуле gutil. Посмотрите как там определена функция С. Конкретно:
Код: Выделить всё
class function TLess.c(a,b:T):boolean;inline;
begin
  c:=a<b;
end;

Теперь мысленно подставьте вместо класса T Ваш класс TMyClass. Работать будет? Нет. Напишите свой класс по аналогии TLess, в котором напишете свою реализацию функции С

Добавлено спустя 3 минуты 25 секунд:
Утверждать не буду , но скорее всего будет у Вас что-то вроде этого
class function TLess.c(a,b:T):boolean;inline;
begin
c:=a.fld1<c.fld1;
end;
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 668
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

Re: Generics из FCL-STL

Сообщение woodhead » 24.07.2018 17:21:25

Может быть переопределить оператор "<" для TMyClass? Правда, тоже не получается:
Код: Выделить всё
interface
uses
  Classes, SysUtils, gset, gutil;

type
   TMyClass = class(TObject)
     fld1 : string;
   end;

  lesslli=specialize TLess<TMyClass>;
  TMyList = specialize TSet<TMyClass, lesslli>;

  operator < (a, b: TMyClass) c : boolean;

implementation

operator < (a, b: TMyClass) c : boolean;
begin
  c:=a.fld1 < b.fld1;
end;

Та же ошибка:
"Error: Operator is not overloaded: "TMyClass" < "TMyClass""
.

Да, ваш вариант рабочий, но не совсем понятно, почему работает без приведения типов, а с приведением не работает:
Код: Выделить всё
interface
uses
  Classes, SysUtils, gset, gutil;

type
  TMyClass = class(TObject)
     fld1 : string;
   end;

  type generic TCompareMyClass<T>=class
    class function c(a,b:T):boolean;inline;
  end;

  lesslli=specialize TCompareMyClass<TMyClass>;
  TMyList = specialize TSet<TMyClass, lesslli>;

implementation

class function TCompareMyClass.c(a,b:T):boolean;inline;
begin
  c:=(a as TMyClass).fld1 < (b as TMyClass).fld1;
end;

В этом случае получаем:
domainunit.pas(190,9) Error: Class or COM interface type expected, but got "<undefined type>"
domainunit.pas(190,32) Error: Class or COM interface type expected, but got "<undefined type>"
Последний раз редактировалось woodhead 24.07.2018 18:31:58, всего редактировалось 1 раз.
woodhead
новенький
 
Сообщения: 21
Зарегистрирован: 24.12.2014 12:23:20

Re: Generics из FCL-STL

Сообщение Ichthyander » 24.07.2018 17:51:17

Как бы и должен был без приведения типов работать, не? А зачем Вам приведение типов?
"Error: Operator is not overloaded: "TMyClass" < "TMyClass""

Суть проблемы не в этом и она не решается переопределение оператора <. Все же проще и я указал на это выше в коде: нельзя между типами класса выполнять сравнение типов (можно наверное как то переопределить оператор, но зачем это нам?!). Но можно выполнять сравнение между полями объекта, как в коде выше:
Код: Выделить всё
c:=a.fld1<b.fld1;

вместо
Код: Выделить всё
с:=a<b
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 668
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

Re: Generics из FCL-STL

Сообщение woodhead » 24.07.2018 18:07:16

Ichthyander писал(а):Как бы и должен был без приведения типов работать, не? А зачем Вам приведение типов?

В этом коде не видно, что параметры функции являются объектами класса TMyClass, у которых есть поле fld1:
Код: Выделить всё
class function TLess.c(a,b:T):boolean;inline;
begin
  c:=a.fld1<c.fld1;
end;
woodhead
новенький
 
Сообщения: 21
Зарегистрирован: 24.12.2014 12:23:20

Re: Generics из FCL-STL

Сообщение Ichthyander » 24.07.2018 18:33:01

Хм... Тогда не знаю.
А что, если вот так указать какая ошибка вылезает? Я не говорю о том, что не видит или не работает автозавершение. Так не компилируется с какой ошибкой? Даже если вынести fld1 в public. Если нет, то затрудняюсь. Не так часто использую генерики :(
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 668
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

Re: Generics из FCL-STL

Сообщение woodhead » 24.07.2018 18:36:51

Ichthyander, я выше писал, что ваш вариант рабочий. Он нормально компилируется, без предупреждений.

Добавлено спустя 33 минуты 31 секунду:
Разобрался. Ошибка была в том, что в модуле gutil ничего не известно о местном переопределении оператора сравнения.
Поэтому можно обойтись без этого модуля, создав нужный класс в своём модуле. При этом отсутствует проблема с приведением типов.
Код: Выделить всё
interface

uses
  Classes, SysUtils, gset;

type
     
  TMyClass = class(TObject)
    fld1 : string;
  end;

  type generic TCompare<T>=class
    class function c(a,b:T):boolean;inline;
  end;

  MyClassCompare=specialize TCompare<TMyClass>;
  TMyList = specialize TSet<TMyClass, MyClassCompare>; 

  operator < (a, b: TMyClass) c : boolean;

implementation   

operator < (a, b: TMyClass) c : boolean;
begin
  c:=a.fld1 < b.fld1;
end;

class function TCompare.c(a,b:T):boolean;inline;
begin
  c:=a < b;
end;
woodhead
новенький
 
Сообщения: 21
Зарегистрирован: 24.12.2014 12:23:20

Re: Generics из FCL-STL

Сообщение zub » 26.07.2018 20:33:30

Код: Выделить всё
generic TSet<T, TCompare>

TSet специализируется типом данных и функцией сравнения этих данных. Функция сравнения нужна чтобы иметь сортированый массив данных.
В простых случаях можно воспользоваться шаблонными сравнивалками из gutil, в сложных нужно писать свою процедуру.

зы. имхо для классов приминыть щаблонные контейнеры не оптимально
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Google [Bot] и гости: 28

Рейтинг@Mail.ru