Delphi是否支持通用方法的显式专业化?

时间:2018-05-02 13:48:14

标签: delphi generics

在C ++中,您可以为模板化函数明确定义唯一的特化,例如(到steal an example

// A generic sort function 
template <class T>
void sort(T arr[], int size)
{
    // code to implement Quick Sort
}

// Template Specialization: A function 
// specialized for char data type
template <>
void sort<char>(char arr[], int size)
{
    // code to implement counting sort
}

有没有办法用Delphi泛型方法做等效的工作?当我尝试

function TryStrConv<T>(S: string; var Val: T): boolean;
function TryStrConv<float>(S: string; var Val: float): boolean;

我收到有关如何使用Overload指令的警告。

我希望获得的是一种编写泛型TryStrConv的方法,其中默认实例化返回false并且什么都不做,而int和float实例化,我想明确提供,使用{ {1}}和TryStrToInt。或者,如果我在德尔福有一个通用的转换工具,我很想知道它。

感谢。

2 个答案:

答案 0 :(得分:5)

您无法在声明中填写泛型参数。您可以使用一个泛型方法重载,也可以使用一个不通用的方法:

function TryStrConv<T>(S: string; var Val: T): boolean; overload;
function TryStrConv(S: string; var Val: Extended): boolean; overload;

但需要注意的是,它只选择Extended的非泛型,而不是Delphi的其他浮点类型,如Double或Single。

另一种方法是,如果您使用的是Delphi XE7或更高版本,则可以使用新的内部函数来分支泛型方法实现(它会在编译时解析,并且会消除未执行的路径)。例如,它可能看起来像这样(我省略了TryStrConv方法的类型,但是你知道在Delphi中你不能有通用的独立例程,但它们必须是某种类型的方法,即使只是静态的):

function TryStrConv<T>(S: string; var Val: T): boolean;
begin
  if GetTypeKind(T) = tkFloat then
  begin
    // do stuff with val being a float type, still need to handle the different float types though 
    case GetTypeData(TypeInfo(T)) of
      ftDouble: DoStuffWithDouble; 
      // if you need to pass Val here you might need to do some pointer
      // ref/deref hardcasts like PDouble(@Val)^ because otherwise you 
      // are not allowed to cast type T to Double (or any other type)
      ....
    end; 
  else
    Result := False;
end;

答案 1 :(得分:0)

你可以做类似的事情:

Type
  TCalc = record
    class function TryStrConv(S: string; var Val: Double): boolean; overload; static;
    class function TryStrConv(S: string; var Val: integer): boolean; overload; static;
    class function TryStrConv<T>(S: string; var Val: T): boolean;  overload; static;
  end;

{ TCalc }

class function TCalc.TryStrConv(S: string; var Val: Double): boolean;
begin
  Result := TryStrToFloat(s,Val);
end;

class function TCalc.TryStrConv(S: string; var Val: integer): boolean;
begin
  Result := TryStrToInt(S,Val);
end;

class function TCalc.TryStrConv<T>(S: string; var Val: T): boolean;
begin
  Result := false;
end;

并测试:

var
  iVal : Integer;
  dVal : Double;
  sVal : String;
  ok : Boolean;
begin
  ok := TCalc.TryStrConv('12',iVal);
  WriteLn(ok,' ',iVal);                  // True 12
  ok := TCalc.TryStrConv('12',dVal);    
  WriteLn(ok,' ',dVal);                  // True 1.2 E+1
  ok := TCalc.TryStrConv('12',sVal);
  WriteLn(ok,' ',sVal);                  // False
  ReadLn;
end.

正如Stefan所说:你必须为每个浮点类型编写一个特定的函数。