Передача Порядкового Параметра - PullRequest
4 голосов
/ 04 апреля 2011

Можно ли написать метод, который принимает любой порядковый тип в качестве параметра?Так же, как Inc () или High ()?

Я использую Delphi 2007

Ответы [ 3 ]

6 голосов
/ 04 апреля 2011

Вам нужно будет использовать нетипизированный параметр :

procedure Foo(const ordinal);

или

procedure Foo(var ordinal);

Конечно, вы несколько ограничены в своих действияхвнутри такой процедуры, потому что вы отказались от системы типов.

1 голос
/ 04 апреля 2011

Найден возможный путь, может быть не тот, который вы ожидаете, но, эй, я нашел способ! Используйте Variants. Проблема с передачей параметров без типов в процедуру состоит в том, что вы получаете простой указатель, без информации о типе, поэтому вы не можете ничего с ним сделать. Байты - 1 байт, перечисления до 256 элементов - 1 байт, перечисления до 2 ^ 16 элементов - 2 байта, целые числа - 4 байта (если они не 8). Но есть один тип, который позволяет передавать что-либо и заботится о достаточной информации о типах, чтобы все заработало: Variant. Я намеренно написал следующий пример в Delphi 7, чтобы убедиться, что я случайно не использую какие-либо блага Delphi 2010 или Delphi XE.

Редактировать : Обновлен пример кода для обработки любого типа , который считается * Ordinal Variants.VarTypeIsOrdinal. Это включает в себя все целочисленные типы + логическое значение. По-видимому, Enum рассматривается как байт, так что он тоже его проглатывает.

program Project1;

{$APPTYPE CONSOLE}

uses
  ExceptionLog,
  SysUtils, Variants;

type TSomeEnum = (e0, e1, e2, e3, e4);

procedure DoSomethingWithEnum(V: Variant);
var i: Integer;
    b: Byte;
    lw: LongWord; // Cardinal!
    i64: Integer;
begin
  case VarType(V) of
    varInt64:
      begin
        i64 := V;
        WriteLn(i64);
      end;
    varSmallint, varInteger, varShortInt:
      begin
        i := V;
        WriteLn(i);
      end;
    varByte:
      begin
        b := V;
        WriteLn(b);
      end;
    varWord, varLongWord:
      begin
        lw := V;
        WriteLn(lw);
      end;
    varBoolean:
      begin
        if V then WriteLn('True') else WriteLn('False');
      end;
    else WriteLn('NOT a variant type (type = #' + IntToStr(Ord(VarType(V))));
  end;
end;

var i: Integer;
    b: Byte;
    c: Cardinal;
    enum: TSomeEnum;
    w: Word;
    si: Shortint;

begin
  i := 1;
  b := 2;
  c := 3;
  enum := e4;
  w := 5;
  si := -6;

  DoSomethingWithEnum(i);
  DoSomethingWithEnum(b);
  DoSomethingWithEnum(c);
  DoSomethingWithEnum(enum);
  DoSomethingWithEnum(True);
  DoSomethingWithEnum(w);
  DoSomethingWithEnum(si);

  Readln;
end.
0 голосов
/ 04 апреля 2011

Причина, по которой это трудно сделать, состоит в том, что Inc (x), Dec (x) и другие, такие как Pred (x) и Succ (x), на самом деле генерируются компилятором и, если хотите, просто FunctionСинтаксис стиля сахар по сравнению с внутренней операцией компилятора.

Вы можете, как некоторые люди предлагают, сделать это с перегрузкой, частично с умным использованием обобщений, а некоторые с вариантами.Но ничто не будет так удобно для эмуляции этих функций или точно так же функционально.

Компилятор реализует Inc (), например, для всех упорядоченных типов, включая Enums, Integer и subranges для этих типов (сейчасдовольно неясная особенность классического «виртского» паскаля заключается в том, что у всех типов могут быть определены поддиапазоны для этих типов).

Если вы на самом деле рассказали нам больше о том, что вы делали, возможно, можно было бы подойти ближе.Но общий ответ: нет, даже нет исходного кода для Inc и Dec, потому что это примитивы компилятора.Если для функции Inc был исходный код RTL, вы можете посмотреть на него и адаптировать его.

inc (x) может быть определено как x: = Succ (x), но как тогда определить Succ (x)?Как х: = Inc (х)?Ты видишь.В какой-то момент, компилятор "магия" вступает во владение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...