如何在 Free Pascal 3.2.2 中实现一个简单的通用 Max 函数。这是我迄今为止的尝试:
文件:cmn.pas
interface
...
generic function Max<U>(a, b: U): U;
generic function Min<U>(a, b: U): U;
...
implementation
...
generic function Max<U>(a, b: U): U;
begin
if a < b then
begin
Exit(b);
end
else
begin
Exit(a);
end;
end;
generic function Min<U>(a, b: U): U;
begin
if b < a then
begin
Exit(b);
end
else
begin
Exit(a);
end;
end;
此操作失败并出现以下编译器错误:
Free Pascal Compiler version 3.2.2 [2021/05/16] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling ./exm.pas
Compiling cmn.pas
exm.pas(19,15) Error: Generics without specialization cannot be used as a type for a variable
exm.pas(19,43) Error: Generics without specialization cannot be used as a type for a variable
exm.pas(34) Fatal: There were 2 errors compiling module, stopping
Fatal: Compilation aborted
Error: /home/sg/temp/pascal/bin/ppcx64 returned an error exitcode
这是许多基于泛型的编程技术的普遍问题,并且对泛型声明本身进行严格的语法验证。
只是为了给你一个想法:我的意思是泛型不像 C++ template 那样工作。您可以编写一个模板,其中像
if a < b
这样的条件没有预定义的意义,因为 a
和 b
的类型在模板实例化之前是未知的,并且代码将编译直到它面对模板实例化(当泛型对于 a < b
肯定未定义的类型,例如某些结构,类型成为完整类型。
然而,在基于泛型的技术中,例如 Pascal 或 C#,即使没有实例化和验证,泛型也会被编译。为了使比较
a < b
有效,您需要将泛型专门化为定义它的类型。不幸的是,它使用泛型将数值算法推广到许多数值类型几乎毫无用处,因为在某些时候你可能需要使用不同的数值类型来编写同一事物的许多变体。
不过,如果你想硬着头皮,还是有办法的。从理论上讲,如果您计划编写许多泛化到某些数值类型的数值算法,那么它可能会有所回报。也许只是理论上的,因为它需要相当大的努力,以及大量非常无聊的工作。我在一篇关于 C# 的文章中了解到了它(抱歉,我没有记录该材料的链接),它也适用于 Free Pascal。
根据这种方法,您仍然需要编写所有原始数字操作,并且多次编写您想要处理的数字类型的数量,并将它们打包在类中,每个数字类型一个类。我可以简单地描述一下,因为这是一个很长的故事。
Number
。+
、-
、*
、/
等,以及基本函数,例如 sin
、ln
、等等Number
派生的类型。这些类需要引入这个底层类型的私有字段,我们称之为 value
。在这种类型中,重写 Number
中声明的所有抽象(因此是虚拟)函数,并使用 value
实现所有这些函数。这里没有泛型,您需要分别手动定义每个派生类以及每个运算符和数字函数。这样,如果这些变量是派生类型的实例,则 sin(p)
等函数和 a + b
等运算符将为 p
、a
和 b
定义。Numeric
派生的类的每个组合定义数字函数和运算符,但这比上一步更大、更无聊。generic constraint
将泛型参数类型限制为 Numeric
。Numeric
派生的一个或另一个类作为实际的泛型参数。这样,泛型参数每次都会满足泛型约束,因为它是从Numeric
导出的。您可以在此处阅读有关 Free Pascal 中约束的使用的信息:https://www.freepascal.org/docs-html/ref/refse55.html.
不用说,如果你只需要实现像
Max
:-) 这样的少数功能,那么大量而无聊的工作在实践中很难得到回报。
当您想要实现许多数值算法并希望使它们适用于多种原始数值类型时,它可能会获得回报。如果您想要添加结构化数字类型(例如向量、矩阵和其他数学构造),它会特别有用。此外,在这种情况下,要使用不同的原始数字类型,与仅使用原始数字类型相比,您需要付出一些性能成本。