Шаблоны (Templates) = Generic
Модератор: Модераторы
- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
- Sergei I. Gorelkin
- энтузиаст
- Сообщения: 1409
- Зарегистрирован: 24.07.2005 14:40:41
- Откуда: Зеленоград
- *vmr
- постоялец
- Сообщения: 168
- Зарегистрирован: 08.01.2007 00:46:07
- Откуда: Киев
- Контактная информация:
Для тех кто еще сомневается в многопроходности 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"
Увы все будет как в С++.
Файл compiler\psub.pas:
файл 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 писал(а):Мне вот, что интересно. Эти женерики будут плодить шаблонные копии как в С++....
Увы все будет как в С++.
Файл 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- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
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;Код: Выделить всё
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) ) );
Замечания:
1. компилятор может все это проделать автоматически имея описание шаблона (и скрыть все это дело от посторонних глаз)
2. для шаблонов нужно будет использовать немного "другие интерфейсы" (назовем их "шаблонными интерфейсами"), т.к.
- 1-х с обычными интерфейсами у нас нет GetObjectFromIntrf,
2-х нет возможности прикрепить "шаблоный интерфейс" к объекту, который уже был скомпилирован,
3-х "шаблонному интерфейсу" не нужен (скорее всего, но есть еще сомнения) счетчик ссылок.
3. проблема пункта 2, решаема.
4. все это дело будет так же эффективно как и обычные виртуальные вызовы.
- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
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))) )^;
shade писал(а):В принципе не вижу пользы от примения шаблонов к простым типам, но если очень нужно, то компилятор может применить "шаблонный интерфейс" и к простому типу
А я не вижу пользы от генериков с классами
- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
Накатал небольшой примерчик (min для типа Integer и AnsiString):
файл generic.rar http://fsaver.hut1.ru/shell.php?user=shade
или "прямая" ссылка http://fsaver.hut1.ru/users/shade/generic.rar
PS: тестил в Delphi, так что не серчайте если в FPC что-то не так.
файл 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
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
Кеш на AGAVA просто убивает, короче вот другая ссылка generic1.rar ( http://fsaver.hut1.ru/users/shade/generic1.rar )
- shade
- энтузиаст
- Сообщения: 879
- Зарегистрирован: 21.02.2006 19:15:48
- Откуда: http://shamangrad.net/
- Контактная информация:
Это то, что должен делать компилятор на основе обычного описания женерика/шаблона.zub писал(а):это всё хаки...
процедура тип_CompareTo - это метод класса, поставляемого в шаблон он один единственный для каждого класса.zub писал(а):к томуже процедур тип_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); и все остальное разрешаться с помошью виртуализации
