Шаблоны (Templates) = Generic

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

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

Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

Мне вот, что интересно. Эти женерики будут плодить шаблонные копии как в С++ или все таки намудрили как-нибудь так, чтобы была лишь одна версия кода за которой скрываются неявные преобразования TObject <-> Pointer??
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Файлы pass_1.pas и pass_2.pas в папке исходников наводят на мысль, что не такой уж он и однопроходный :roll:
Аватара пользователя
*vmr
постоялец
Сообщения: 168
Зарегистрирован: 08.01.2007 00:46:07
Откуда: Киев
Контактная информация:

Сообщение *vmr »

Для тех кто еще сомневается в многопроходности FPC:
файл compiler\i386\popt386.pas, в интерфейсной секции обьявлены процедуры
procedure PrePeepHoleOpts(asml: TAsmList; BlockStart, BlockEnd: tai);
procedure PeepHoleOptPass1(asml: TAsmList; BlockStart, BlockEnd: tai);
procedure PeepHoleOptPass2(asml: TAsmList; BlockStart, BlockEnd: tai);
procedure PostPeepHoleOpts(asml: TAsmList; BlockStart, BlockEnd: tai);

Далее по коду видно кучу комментов типа:
// changes certain "imul const, %reg"'s to lea sequences
// change "imul $1, reg1, reg2" to "mov reg1, reg2"
// the following if-block removes all code between a jmp and the next label, because it can never be executed
// change "cmp $0, %reg" to "test %reg, %reg"

shade писал(а):Мне вот, что интересно. Эти женерики будут плодить шаблонные копии как в С++....

Увы все будет как в С++. :cry:
Файл compiler\psub.pas:

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

hp:=tdef(tobjectdef(ttypesym(p).typedef).symtable.DefList[i]);
if hp.typ=procdef then
  begin
     if assigned(tprocdef(hp).genericdef) and
     (tprocdef(hp).genericdef.typ=procdef) and
      assigned(tprocdef(tprocdef(hp).genericdef).generictokenbuf) then
      begin
         oldcurrent_filepos:=current_filepos;
          current_filepos:=tprocdef(tprocdef(hp).genericdef).fileinfo;
          current_tokenpos:=current_filepos;
          current_scanner.startreplaytokens
             (tprocdef(tprocdef(hp).genericdef).generictokenbuf);
          read_proc_body(nil,tprocdef(hp)); // <--- !!!!
// Parses the procedure directives, then parses the procedure body, then
// generates the code for it(комментарий на read_proc_body)
           current_filepos:=oldcurrent_filepos;
       end
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

shade писал(а):Мне вот, что интересно. Эти женерики будут плодить шаблонные копии как в С++ или все таки намудрили как-нибудь так, чтобы была лишь одна версия кода за которой скрываются неявные преобразования TObject <-> Pointer??

будут плодить. иначе смысла в них нету
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

Понятно, но на счет смысла спорно...
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

shade писал(а):, чтобы была лишь одна версия кода за которой скрываются неявные преобразования TObject <-> Pointer??

если такое преобразование возможно, то это решается правильной архитектурой наследования типов а не генериками. генерики какраз для типов которые которые привести друг к другу нельзя
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

zub писал(а):если такое преобразование возможно, то это решается правильной архитектурой наследования типов а не генериками. генерики какраз для типов которые которые привести друг к другу нельзя

Рассмотрим пример:

Допустим у нас есть шаблонизированная функция min
(приведу C++ подобный синтаксис шаблонов, ибо с женериками еще не разобрался)

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

template <class TObj>
function min(A, B: TObj): TObj;
begin
  if A.CompareTo(B) < 0 then Result := A
  else Result := B;
end;

Теперь мы хотим его использовать:

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

var A, B, C: TSomeObj;
C := min(A, B);

Что требуется от TSomeObj? соблюсти некоторый интерфейс, в данном случае иметь метод function CompareTo(X: TSomeObj): Integer;
Что может сделать компилятор? создать неявный интерфейс:

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

min_TObj = interface
  function CompareTo(X: min_TObj): Integer;
end;
теперь функцию min можно переписать следующим образом:

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

function min(A, B: min_TObj): min_TObj;
begin
  if A.CompareTo(B) < 0 then Result := A
  else Result := B;
end;
Один экземпляр :!:
Теперь вызов:

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

var A, B, C: TSomeObj;
C := TSomeObj( GetObjectFromIntrf( min(A as min_TObj, B as min_TObj) ) );
нужна еще (inline) функция function GetObjectFromIntrf(I: IUnknown): TObject; которая умеет из интерфейса извлекать объект, который этот интерфейс реализует.

Замечания:
1. компилятор может все это проделать автоматически имея описание шаблона (и скрыть все это дело от посторонних глаз)
2. для шаблонов нужно будет использовать немного "другие интерфейсы" (назовем их "шаблонными интерфейсами"), т.к.
    1-х с обычными интерфейсами у нас нет GetObjectFromIntrf,
    2-х нет возможности прикрепить "шаблоный интерфейс" к объекту, который уже был скомпилирован,
    3-х "шаблонному интерфейсу" не нужен (скорее всего, но есть еще сомнения) счетчик ссылок.

3. проблема пункта 2, решаема.
4. все это дело будет так же эффективно как и обычные виртуальные вызовы.
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

непонял к чему тут интерфейсы? /edit помоему тут можно обойтись только виртуальными методами
все вышесказанное применимо только к class`ам. как быть с простыми типами?
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

zub писал(а):непонял к чему тут интерфейсы?
все вышесказанное применимо только к class`ам. как быть с простыми типами?

В принципе не вижу пользы от примения шаблонов к простым типам, но если очень нужно, то компилятор может применить "шаблонный интерфейс" и к простому типу.

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

function Integer_CompareTo(var A, B: Integer): Integer;
begin
  Result := A - B;
end;

type
  TemplateIntrfRec = record
    VMT: Pointer;
    Obj: Pointer;
  end;

var min_IntegerVMT: array [0..0] of Pointer = (@Integer_CompareTo);

function IntegerAsTemplateIntrf(var X: Integer): TemplateIntrfRec; inline;
begin
  Result.VMT := @min_IntegerVMT;
  Result.Obj := @X;
end;

function GetObjectFromIntrf(var TI: TemplateIntrfRec): Pointer; inline;
begin
  Result := TI.Obj;
end;

var A, B, C: Integer;

C := PInteger( GetObjectFromIntrf(min(IntegerAsTemplateIntrf(A), IntegerAsTemplateIntrf(B))) )^;


:wink:
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

shade писал(а):В принципе не вижу пользы от примения шаблонов к простым типам, но если очень нужно, то компилятор может применить "шаблонный интерфейс" и к простому типу

А я не вижу пользы от генериков с классами :wink:, там все можно сделать грамотным наследованием и виртуальными методами. вся сила генериков с простыми типами. теперь ненадо будет писать кучу контейнеров для хранения простых данных
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

Накатал небольшой примерчик (min для типа Integer и AnsiString):
файл generic.rar http://fsaver.hut1.ru/shell.php?user=shade
или "прямая" ссылка http://fsaver.hut1.ru/users/shade/generic.rar

PS: тестил в Delphi, так что не серчайте если в FPC что-то не так.
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

Блин, допустил небольшую ошибочку:
min_AnsiStringVMT долджна быть такой:
min_AnsiStringVMT: array [0..0] of Pointer = (@AnsiString_CompareTo);

Сейчас новый файл закачаю.
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

Кеш на AGAVA просто убивает, короче вот другая ссылка generic1.rar ( http://fsaver.hut1.ru/users/shade/generic1.rar )
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

это всё хаки... к томуже процедур тип_CompareTo получится столькоже сколько типов. чем это лучше создания генериком своих проуедур для каждого типа?
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

zub писал(а):это всё хаки...
Это то, что должен делать компилятор на основе обычного описания женерика/шаблона.
zub писал(а):к томуже процедур тип_CompareTo получится столькоже сколько типов. чем это лучше создания генериком своих проуедур для каждого типа?
процедура тип_CompareTo - это метод класса, поставляемого в шаблон он один единственный для каждого класса.
И процедура min тоже физически одна в противовес обычным шаблонам в C++, которые создают свой экземпляр для каждого типа, с которым используется.

Поясню различие на примере:
C++ (и то что сейчас пытаются реализовать в FPC):

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

template <class TSomeType>
TSomeType min(TSomeType A, TSomeType B)
{
 if ( A.CompareTo(B) > 0 ) return A; else return B; }

При использовании

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

class TObj1 { int a;
 TObj1(int X): a(X) {}
 int CompareTo(TObj X) { return a - X.a; }
};
class TObj2 {
 float a;
 TObj2(float X): a (X) {}
 int CompareTo(TObj X) { return int(a - X.a); }
 };
void test()
{
  min(TObj1(5), TObj2(80));
  min(TObj2(1.2), TObj2(0.7));
}
Создается две функции
TObj1 min<TObj1>(TObj1, TObj1); и TObj2 min<TObj2>(TObj2, TObj2);

Если сделать как я описал, то будет одна функция TemplateInterface min(TemplateInterface, TemplateInterface); и все остальное разрешаться с помошью виртуализации
Ответить