Как объявить процедурный тип для class ... static?

Общие вопросы программирования, алгоритмы и т.п.

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

mgear
новенький
Сообщения: 19
Зарегистрирован: 25.01.2015 18:29:56

Как объявить процедурный тип для class ... static?

Сообщение mgear »

Нигде в интернетах ответа не смог найти. Или меня одного это интересует, или задачка не решается в рамках FPC. При этом в дельфи пашет как от нефиг делать.

Есть callback функции, объявленные через процедурный тип, чтобы использоваться во внешней библиотеке. Их там две штуки, но для простоты приведу одну:

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

type
  pcre2_malloc_func = function(size:PCRE2_SIZE; p:pointer):pointer; cdecl;
  function pcre2_general_context_create_16(malloc_f: pcre2_malloc_func; free_f: pcre2_free_proc; memory_data:pointer): p_pcre2_general_context; cdecl; external;

function pcre2_malloc_def(size:PCRE2_SIZE; p:pointer):pointer; cdecl;
begin
  Result := getmem(size);
end;

...
fgeneral_context := pcre2_general_context_create_16(@pcre2_malloc_def, @pcre2_free_def, nil);


Ну и как бы зашибись всё работает. Но это неаккуратненько, доктор. Потому что вспомогательная функция класса объявлена вне класса.

Мы-то на объектном языке пишем, и вызов используется в классе, так что идеологически верно было бы оформить в качестве метода и описать, естественно, как class static, чтоб вызывалась без селфов разных там.

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

    class function malloc_def(size:PCRE2_SIZE; p:pointer):pointer; cdecl; static;


Но в этом случае компилятор ругается:
Error: Incompatible type for arg no. 1: Got "<class method type of function(LongWord;Pointer):^untyped of object;CDecl>", expected "<procedure variable type of function(LongWord;Pointer):^untyped;CDecl>"


Причём в хелпе русским английским языком сказано следующее:
FPC knows static class methods in classes: these are class methods that have the Static keyword at the end. These methods behave completely like regular procedures or functions. This means that:

They do not have a Self parameter. As a result, they cannot access properties or fields or regular methods.
They cannot be virtual.
They can be assigned to regular procedural variables.


Выделено мною. Тем не менее, assign to regular procedural variable не фурычит.
Аватара пользователя
Дож
энтузиаст
Сообщения: 900
Зарегистрирован: 12.10.2008 16:14:47

Сообщение Дож »

Мне не удалось воспроизвести ошибку.

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

[doj@larion ~/temp]$ cat staticproc.pas
{$MODE DELPHI}
type
TFunc = function(Size: Integer; P: Pointer): Pointer; cdecl;
TMyObject = class
  class function malloc_def(Size: Integer; P: Pointer): Pointer; cdecl; static;
end;

class function TMyObject.malloc_def(Size: Integer; P: Pointer): Pointer;
begin
  Result := P;
end;

var
  F: TFunc;

begin
  F := TMyObject.malloc_def;
end.
[doj@larion ~/temp]$ fpc staticproc.pas
/usr/bin/ld: warning: link.res contains output sections; did you forget -T?
[doj@larion ~/temp]$
kazalex
постоялец
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Сообщение kazalex »

Дож писал(а):Мне не удалось воспроизвести ошибку.

{$MODE DELPHI} убери :)
mgear
новенький
Сообщения: 19
Зарегистрирован: 25.01.2015 18:29:56

Сообщение mgear »

Я уж по-всякому корячился, но фантазия иссякла, а воз и ныне там. Даже принудительно тип указателя присвоить не получилось. Компилятор упирается. Не буду, - говорит, - компилировать и всё тут. Несоответствие, - говорит, - типов.

Моде дельфи не хочу. Не по-пацански это. Хочу уметь объявлять тип метода. А то прям как в той песенке получается: жопа есть, а слова нет.
kazalex
постоялец
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Сообщение kazalex »

mgear писал(а):Даже принудительно тип указателя присвоить не получилось.

Хм, странно. У меня с приведением сработало.
mgear
новенький
Сообщения: 19
Зарегистрирован: 25.01.2015 18:29:56

Сообщение mgear »

Ну ок, вот тестовый юнит. Он компилируется. Задача - раскомментировать строчку и скомпилять в режиме objfpc хоть через какое угодно переписывание методов и приведение типов.

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

unit Unit1;

{$mode objfpc}{$H+}

interface

type
  pcre2_malloc_func = function(size:longint; p:pointer):pointer; cdecl;
  pcre2_free_proc = procedure(p1:pointer; p2:pointer); cdecl;

  pcre2_general_context = record end;
  p_pcre2_general_context = ^pcre2_general_context;

  myclass = class
  private
     fgeneral_context: p_pcre2_general_context;
     class function malloc(size:longint; p:pointer):pointer; cdecl; static;
     class procedure free(p1:pointer; p2:pointer); cdecl; static;
  public
     procedure aaa;
  end;

function pcre2_general_context_create_16(malloc_f: pcre2_malloc_func; free_f: pcre2_free_proc; memory_data:pointer): p_pcre2_general_context; cdecl;

implementation

function _malloc(size:longint; p:pointer):pointer; cdecl;
begin
  Result := nil;
end;

procedure _free(p1:pointer; p2:pointer); cdecl;
begin
end;

function pcre2_general_context_create_16(malloc_f: pcre2_malloc_func;
  free_f: pcre2_free_proc; memory_data: pointer): p_pcre2_general_context;
  cdecl;
begin
  Result := nil;
end;

class function myclass.malloc(size: longint; p: pointer): pointer; cdecl;
begin
  Result := nil;
end;

class procedure myclass.free(p1: pointer; p2: pointer); cdecl;
begin

end;

procedure myclass.aaa;
begin
  fgeneral_context := pcre2_general_context_create_16(@_malloc, @_free, nil);
//  fgeneral_context := pcre2_general_context_create_16(@malloc, @free, nil);
end;

end.
kazalex
постоялец
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Сообщение kazalex »

mgear писал(а):Задача - раскомментировать строчку и скомпилять в режиме objfpc хоть через какое угодно переписывание методов и приведение типов.

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

  fgeneral_context := pcre2_general_context_create_16(pcre2_malloc_func(@myclass.malloc), pcre2_free_proc(@myclass.free), nil);
mgear
новенький
Сообщения: 19
Зарегистрирован: 25.01.2015 18:29:56

Сообщение mgear »

kazalex, спасибо!!!

Почему-то паскаль ругается "Error: Illegal type conversion" на pcre2_malloc_func(@malloc), при этом спокойно кушает pcre2_malloc_func(@myclass.malloc). Хотя вызов осуществляется из метода класса, так что уточнение "myclass.", вроде как, избыточное. Вот и поди догадайся. Хорошо хотя бы он не просит "unit1.myclass." :lol: :lol: :lol:
wavebvg
постоялец
Сообщения: 355
Зарегистрирован: 28.02.2008 03:57:35

Сообщение wavebvg »

mgear писал(а):Почему-то паскаль ругается "Error: Illegal type conversion" на pcre2_malloc_func(@malloc), при этом спокойно кушает pcre2_malloc_func(@myclass.malloc). Хотя вызов осуществляется из метода класса, так что уточнение "myclass.", вроде как, избыточное. Вот и поди догадайся. Хорошо хотя бы он не просит "unit1.myclass." :lol: :lol: :lol:

Потому что Вы через ссылку на таблицу в Self пытается вызвать, что недопустимо для компилятора.
Просто это не предусмотрено в самом компиляторе, потому что class метод может быть виртуальным и тогда... Ну в общем тогда нужно все предусмотреть, так что проще запретить стрелять себе в голову, предварительно запретив стрелять в себя с открытыми глазами. Разименовав указатель и правильно пересчитав смещение вы можете вызвать всё, что угодно. Только оно Вам надо?
mgear
новенький
Сообщения: 19
Зарегистрирован: 25.01.2015 18:29:56

Сообщение mgear »

wavebvg писал(а):Только оно Вам надо?

Мне (и, надеюсь, всем прочим юзверятам) надо, чтоб были методы статические без указателей, совместимые по типу с бесклассовыми процедурами. В дельфи они есть. В плюсах есть. В джаве есть. Во фри паскале их нет почему-то. По сути, это является диверсией и надругательством над психикой. Тем этом в официальном хелпе написано, что они есть. Как так?

То есть, если сравнивать с оружием, они мне продают ружжо без бойка с пропиленным стволом. Понятно, что в голову себе не стрельнёшь, но ведь и на зайцев-уток не поохотишься.
kazalex
постоялец
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Сообщение kazalex »

mgear писал(а): По сути, это является диверсией и надругательством над психикой. Тем этом в официальном хелпе написано, что они есть. Как так?

Обычный баг, коих появляется вагон, как только начинаешь писать более-менее сложный код.
mgear
новенький
Сообщения: 19
Зарегистрирован: 25.01.2015 18:29:56

Сообщение mgear »

kazalex, больше похоже на то, что сделано специально.
kazalex
постоялец
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Сообщение kazalex »

mgear, по сообщению об ошибке видно же, что баг:
project1.lpr(53,85) Error: Incompatible type for arg no. 2: Got "<class method type of procedure(Pointer;Pointer) of object;CDecl>", expected "<procedure variable type of procedure(Pointer;Pointer);CDecl>"

Добавлено спустя 37 минут 21 секунду:
Вот еще прикол. В режиме {$mode delphi} прокатывает даже если у методов класса (malloc и free) полностью изменить сигнатуры :mrgreen:

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

class procedure myclass.free();
begin
end;

procedure myclass.aaa;
begin
  fgeneral_context := pcre2_general_context_create_16(@myclass.malloc, @myclass.free, nil);
end;

Проверено на транковом компиляторе.

Добавлено спустя 14 минут 51 секунду:
Но если убрать оператор взятия адреса, то прокатывать перестает :)
Аватара пользователя
alexs
долгожитель
Сообщения: 4066
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь
Контактная информация:

Сообщение alexs »

А написать метод-обёртку над вызовом обращением к процедурной переменной? Заодно в нём можно проверки необходимые на корректность вызова добавить.
А саму процедурную переменную хранить в защищённой секции класса.
mgear
новенький
Сообщения: 19
Зарегистрирован: 25.01.2015 18:29:56

Сообщение mgear »

alexs, именно так сейчас и сделано. Судя по всему, так и останется.
Ответить