我可以限制(编译或运行时)泛型为char的数组[0..n] [英] Can I restrict (compile or runtime) a generic to being an array [0..n] of char

查看:74
本文介绍了我可以限制(编译或运行时)泛型为char的数组[0..n]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个程序,该程序具有许多结构,这些结构定义为char和记录的静态数组(通常由char数组组成,但这并不重要).

I have a program with a lot of structures defined as static arrays of char and records (usually consisting of arrays of char, but that's not so important).

我正在尝试为这些结构创建一个通用接口,以便可以将它们传递到后端C DLL.

I am trying to create a generic interface for these structures, so they can be passed to a back-end C DLL.

我可以使用< T:record> 约束来处理所有类型的记录,但是 char的array [0..n] 犯规不可为空的值类型"规则.

I am able to handle all types of records by using the <T: record> constraint, but array[0..n] of char falls foul of the 'non-nullable value type' rule.

我可以通过为不同的静态数组声明类型来使用不受约束的泛型( TMyArray = array [0..5] char -很好,因为它已存在于现有代码中),但是我需要失去我的< T:record> 约束.由于我的代码不适用于类或动态数组,因此我希望能够将 T 限制为char的记录或静态数组.

I can use unconstrained generics by declaring types for my different static arrays (TMyArray = array[0..5] of char - this is fine, as it's already there in existing code), but I need to lose my <T: record> constraint. As my code will not work with classes nor dynamic arrays I'd like to be able to restrict T to being either a record or static array of char.

我可以有两个构造函数,分别带有和不带有 record 约束.然后,我可以使用旧式RTTI来测试其非约束类型是否为数组:

I am able to have two constructors with and without the record constraint. I can then test that it the unconstrained type is an array by using old-style RTTI:

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

但是我认为我不能检查所包含的类型是否为char?2010 RTTI抱怨T必须是一门课,所以我也不认为这是行进者.通过创建仅包含我的静态char数组的记录,我可以在某种程度上解决它,但是这感觉有点模糊,并且在代码中看起来很笨拙.

but I don't think I can check that the contained type is a char? 2010 RTTI complains that T must be a class, so I don't think that's a goer either. I can get around it somewhat by creating records containing only my static char array, but that feels a bit of a fudge and will look quite clumsy in code.

推荐答案

这是编译器缺陷.固定长度的数组是不可为空的值类型.该缺陷仍然存在于Delphi 10 Seattle中.该程序无法编译:

This is a compiler defect. A fixed length array is a non-nullable value type. The defect is still present in Delphi 10 Seattle. This program fails to compile:

{$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错误] E2512类型参数"T"必须为非空值类型

[dcc32 Error] E2512 Type parameter 'T' must be a non-nullable value type

因此,我想您将不得不使用RTTI通过运行时检查来处理此问题.您当然可以做到.该程序演示:

So, I guess you will have to handle this with a runtime check using RTTI. Which you can certainly do. This program demonstrates:

{$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 .因此,这使您可以执行以下操作:

Note that ord(tkWChar) == 9. So, this gives you the means to do the following:

  1. 检测类型为数组.
  2. 检查它是否具有单个尺寸.
  3. 检查元素类型是否符合预期.
  4. 检查元素计数是否符合预期.

这就是检查类型是否符合要求所需的全部信息.

That's all the information you need to check that the type meets your requirements.

这篇关于我可以限制(编译或运行时)泛型为char的数组[0..n]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆