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

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

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

Сообщение shade » 08.01.2007 23:46:15

Мне вот, что интересно. Эти женерики будут плодить шаблонные копии как в С++ или все таки намудрили как-нибудь так, чтобы была лишь одна версия кода за которой скрываются неявные преобразования TObject <-> Pointer??
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение Sergei I. Gorelkin » 08.01.2007 23:48:27

Файлы pass_1.pas и pass_2.pas в папке исходников наводят на мысль, что не такой уж он и однопроходный :roll:
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение *vmr » 09.01.2007 01:52:49

Для тех кто еще сомневается в многопроходности 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
Аватара пользователя
*vmr
постоялец
 
Сообщения: 168
Зарегистрирован: 08.01.2007 01:46:07
Откуда: Киев

Сообщение zub » 09.01.2007 11:31:50

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

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

Сообщение shade » 09.01.2007 11:52:19

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

Сообщение zub » 09.01.2007 12:01:53

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

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

Сообщение shade » 09.01.2007 12:42:35

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. все это дело будет так же эффективно как и обычные виртуальные вызовы.
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение zub » 09.01.2007 13:05:27

непонял к чему тут интерфейсы? /edit помоему тут можно обойтись только виртуальными методами
все вышесказанное применимо только к class`ам. как быть с простыми типами?
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Сообщение shade » 09.01.2007 13:23:28

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:
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение zub » 09.01.2007 13:30:13

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

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

Сообщение shade » 09.01.2007 13:59:20

Накатал небольшой примерчик (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 20:15:48
Откуда: http://shamangrad.net/

Сообщение shade » 09.01.2007 14:07:39

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

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

Сообщение shade » 09.01.2007 14:13:36

Кеш на AGAVA просто убивает, короче вот другая ссылка generic1.rar ( http://fsaver.hut1.ru/users/shade/generic1.rar )
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение zub » 09.01.2007 14:28:44

это всё хаки... к томуже процедур тип_CompareTo получится столькоже сколько типов. чем это лучше создания генериком своих проуедур для каждого типа?
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Сообщение shade » 09.01.2007 14:46:26

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); и все остальное разрешаться с помошью виртуализации
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Пред.След.

Вернуться в Free Pascal Compiler

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

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Рейтинг@Mail.ru