2015-12-07 4 views
2

У меня есть программа с множеством структур, определяемых как статические массивы символов и записей (обычно состоящие из массивов char, но это не так важно).Могу ли я ограничить (компиляцию или время выполнения) родовое число как массив [0..n] из char

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

Я могу обрабатывать записи всех типов с помощью ограничения <T: record>, но array[0..n] of char не соответствует правилу 'не-nullable value type'.

Я могу использовать неограниченные дженерики, объявляя типы для разных статических массивов (TMyArray = array[0..5] of char - это прекрасно, поскольку он уже существует в существующем коде), но мне нужно потерять ограничение <T: record>. Поскольку мой код не будет работать с классами или динамическими массивами, я бы хотел ограничить T как статичным или статическим массивом символов.

Я могу иметь два конструктора с ограничением record. то я могу проверить, что ним непринужденный тип представляет собой массив с помощью старого стиля RTTI:

var 
    l: PTypeInfo; 
begin 
    l := TypeInfo(T); 
    assert(l.Kind = tkArray); 
end; 

, но я не думаю, что я могу проверить, что содержавшийся типом является символом? 2010 RTTI жалуется, что T должен быть классом, поэтому я не думаю, что это тоже. Я могу немного обойти его, создав записи, содержащие только мой статический массив символов, но это немного притворно и будет выглядеть довольно неуклюжим в коде.

+0

можете ли вы преобразовать массив в расширенную запись с помощью класса-оператора? Неявные машинные приемы в и из массива? –

+0

Я предполагаю, что это возможность, но их очень много, поэтому на самом деле не нужно создавать эту структуру для более 50 типов данных. Он предназначен только для внутреннего использования, поэтому проверка времени выполнения с использованием RTTI, как принято ниже, прекрасна до тех пор, пока компилятор не будет исправлен, и мы обновим его. –

ответ

3

Это дефект компилятора. Массив фиксированной длины - это тип значения, который не является нулевым. Дефект все еще присутствует в Delphi 10 Seattle. Эта программа не для компиляции:

{$APPTYPE CONSOLE} 

type 
    TFoo = record 
    class procedure Bar<T: record>(const arg: T); static; 
    end; 

class procedure TFoo.Bar<T>(const arg: T); 
begin 
end; 

type 
    TArr = array [0..0] of char; 

var 
    Arr: TArr; 

begin 
    TFoo.Bar<TArr>(Arr); 
end. 

Ошибки:

[dcc32 Error] Параметр E2512 Типа 'T' должен быть ненулевым типом значения

Итак, я угадайте, вам придется обработать это с помощью проверки времени выполнения с помощью RTTI. Что вы, безусловно, можете сделать. Эта программа демонстрирует:

{$APPTYPE CONSOLE} 

uses 
    Rtti, TypInfo; 

type 
    TFoo = record 
    class procedure Bar<T>(const arg: T); static; 
    end; 

class procedure TFoo.Bar<T>(const arg: T); 
var 
    TypInfo: PTypeInfo; 
    ArrayTypeData: TArrayTypeData; 
begin 
    TypInfo := TypeInfo(T); 
    if TypInfo.Kind = tkArray then begin 
    ArrayTypeData := GetTypeData(TypInfo).ArrayData; 
    Writeln(ord(ArrayTypeData.ElType^.Kind)); 
    Writeln(ArrayTypeData.Size); 
    Writeln(ArrayTypeData.ElCount); 
    Writeln(ArrayTypeData.DimCount); 
    end; 
end; 

type 
    TArr = array [1..32] of char; 

var 
    Arr: TArr; 

begin 
    TFoo.Bar<TArr>(Arr); 
    Readln; 
end. 

Выход:

 
9 
64 
32 
1 

Обратите внимание, что ord(tkWChar) == 9. Таким образом, это дает вам возможность сделать следующее:

  1. Определите, что тип представляет собой массив.
  2. Убедитесь, что он имеет одно измерение.
  3. Убедитесь, что тип элемента соответствует ожидаемому.
  4. Убедитесь, что количество элементов соответствует ожидаемому.

Это все, что вам нужно для проверки того, что тип соответствует вашим требованиям.

+0

Спасибо, я пробовал делать подобное, но используя TArrayTypeData, а не PTypeData, и полученный в результате мусор заставил меня думать, что я не получил RTTI, а не тот факт, что я выбрал неправильную вещь. Я буду QC ошибкой компилятора, если он еще не зарегистрирован –