Ка правильно написать энумератор по записи...

Вопросы программирования на Free Pascal, использования компилятора и утилит.

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

Ответить
Аватара пользователя
beria
постоялец
Сообщения: 130
Зарегистрирован: 29.09.2016 07:57:13

Ка правильно написать энумератор по записи...

Сообщение beria »

Написал для цикла нечто следующее и оно компилируется...

Код: Выделить всё

TDyn = record
    FCurrent: sizeInt;
...........
    class operator Initialize(var aRec: TDyn);
    class operator Finalize(var aRec: TDyn);
    function MoveNext: boolean; inline;
    property Current: sizeInt read FCurrent;
    class operator enumerator(i: sizeInt): TDyn;
  end;      
........
function TDyn.MoveNext: boolean;
begin
  Inc(FCurrent, ItemSize);
  Exit(FCurrent < High);
end;
class operator TDyn.enumerator(i: sizeInt): TDyn;
begin
  Result.FCurrent := -1;
end;

Но в основной программе энумератор не видится

Код: Выделить всё

var
ar2: TDyn; 
i: sizeint;
begin
for i in ar2 do Write(' ', i);   /// project1.lpr(129,12) Ошибка: Cannot find an enumerator for the type "TDyn"
Что я не так сделал.. Просто очень мало про энумераторы, применительно к записям вообще есть....
iskander
энтузиаст
Сообщения: 630
Зарегистрирован: 08.01.2012 18:43:34

Сообщение iskander »

beria писал(а):Написал для цикла нечто следующее и оно компилируется...
Вроде не должно бы оно компилироваться.
Должно быть или так

Код: Выделить всё


TDyn = record
    FCurrent: sizeInt;
...........
    class operator Initialize(var aRec: TDyn);
    class operator Finalize(var aRec: TDyn);
    function GetEnumerator: TDyn; 
    function MoveNext: boolean; inline;
    property Current: sizeInt read FCurrent;
  end;
  
или так

Код: Выделить всё

TDyn = record
    FCurrent: sizeInt;
...........
    class operator Initialize(var aRec: TDyn);
    class operator Finalize(var aRec: TDyn);
    function MoveNext: boolean; inline;
    property Current: sizeInt read FCurrent;
  end;
.....
operator Enumerator(var{?} d: TDyn): TDyn;

Кстати использование managed record в качестве энумератора не кажется хорошей идеей, в багтрекере висел связанный с этим баг.
Аватара пользователя
beria
постоялец
Сообщения: 130
Зарегистрирован: 29.09.2016 07:57:13

Сообщение beria »

Как минимум ваш первых вариант компилируется до конца, но все равно хрень полная.
Как выяснилось в function TDyn.MoveNext: boolean; не определены (там мусор) любые переменные, TDyn.... Как это - я вот прямо сейчас в шоке. Такое чувство, что при этом неявно создается ещё один экземпляр записи..... Не помню чтобы было в каком-то мануале...

Добавлено спустя 11 часов 7 минут 25 секунд:
Рабочий вариант....

Код: Выделить всё

  function TDyn.GetEnumerator: TDyn;
  begin
    Result:=self;
    Result.FCurrent := -1;
  end;   
iskander
энтузиаст
Сообщения: 630
Зарегистрирован: 08.01.2012 18:43:34

Сообщение iskander »

beria писал(а):...
Рабочий вариант....
Воля ваша, конечно, но на всякий случай гляньте вот на этот баг.
Аватара пользователя
beria
постоялец
Сообщения: 130
Зарегистрирован: 29.09.2016 07:57:13

Сообщение beria »

iskander писал(а):
beria писал(а):...
Рабочий вариант....
Воля ваша, конечно, но на всякий случай гляньте вот на этот баг.
Правится вложенной структурой в записи.
То есть примерно так.. это для энумератора по адресу...

Код: Выделить всё

  TDyn = record
.......
   procedure Z; inline;
    procedure Done;
    class operator Initialize(var aRec: TDyn);
    class operator Finalize(var aRec: TDyn);
  type
    TDynEn = record
      FCurrent: Pointer;
      FinisCurrent: Pointer;
      function MoveNext: boolean; inline;
      property Current: Pointer read FCurrent;
    end;
  var
    En: TDynEn;
    function GetEnumerator: TDynEn; inline;
  end;                                        
И все работает...
iskander
энтузиаст
Сообщения: 630
Зарегистрирован: 08.01.2012 18:43:34

Сообщение iskander »

Согласен, стало гораздо лучше, но почему энумератор непременно должен быть вложенной структурой?
Аватара пользователя
beria
постоялец
Сообщения: 130
Зарегистрирован: 29.09.2016 07:57:13

Сообщение beria »

iskander писал(а):Согласен, стало гораздо лучше, но почему энумератор непременно должен быть вложенной структурой?
Все очень просто.
Из-за ошибки в FPC, которую никак не правят уже почти год, использование в записи Initialize/Finalize и энумератора просто невозможно одновременно ибо энумератор тоже вызывает Initialize/Finalize и это никак не пресечь. ... ((((( Поэтому и приходится энумератор выносить во внешнюю структуру. Ну в данном случае вложенную ибо так проще...
Но проблема все равно есть - как именно штатными средствами языка из вложенной структуры получить поля корневой.
То есть у нас есть некая функция.....
function TDyn.TDynEn.MoveNext: boolean;
begin
// там изменяется счетчик
end;

Как в этой функции получить не поля TDynEn, а поля TDyn?????
При этом через адрес, то есть грязным образом все работает ибо self = @TDyn.En, а дальше через смещение можно получить любое поле...
TDyn.<имя поля> или просто <имя поля> не проходят компиляцию...
iskander
энтузиаст
Сообщения: 630
Зарегистрирован: 08.01.2012 18:43:34

Сообщение iskander »

beria писал(а):Ну в данном случае вложенную ибо так проще...
Не только, есть ещё один довод в пользу вложенной структуры: меньше захламляется пространство имён.
beria писал(а):как именно штатными средствами языка из вложенной структуры получить поля корневой.
Экземпляр вложенной структуры должен иметь адрес экземпляра корневой структуры, иначе никак.
Ответить