5

我在 Fortran 2003 中编写了一些代码,这些代码用稀疏矩阵做了很多线性代数。我正在尝试利用新标准的一些更抽象的特性,这样我就有了更简单的程序,而没有太多重复的代码。

我有一个过程solver,它接受一个矩阵、一些向量、所使用的迭代方法的容差等。我将一个指针传递给一个调用matvec它的过程;matvec是我们用于矩阵向量乘法的子程序。

问题是,有时一个过程会在发送到该过程的通常matvec参数之上接受额外的参数。colorlist, color1, color2我可以想到几种处理方法。

第一个想法:定义两个不同的抽象接口matvec1matvec2两个不同的求解器。这可行,但这意味着复制一些代码,这正是我试图避免的。

另一个想法:保持相同的抽象接口matvec,并使额外的参数colorlist, color1,color2可选。这意味着在每个 matvec 例程中使它们成为可选的——即使是那些它们不是真正可选的,以及它们甚至根本不使用的例程。如果我这样做,我肯定会下地狱的。

我能想到很多其他不是最佳的解决方案。我想对此提出一些意见——我确信有一些优雅的方法可以做到这一点,我只是不确定它是什么。

4

2 回答 2

5

问题实际上是,每次调用过程时是否必须传递附加参数(因为它们在两次调用之间发生变化),或者它们可以在某个时候初始化,然后在函数中使用。在后一种情况下,您可以创建一个具有抽象接口的类,该接口matvec使用基本参数定义您的子例程。然后,您可以使用更专业的类扩展该类,这些类可以包含所需的其他选项。它们仍然必须定义与matvec父类相同的接口(具有相同的参数列表),但是当matvec调用它们的过程时,它们可以使用存储在它们中的附加值。

您可以在此答案中找到类似案例的详细示例(查找显示的第二个示例module rechercheRacine)。

于 2013-03-07T08:01:50.780 回答
2

matvec您可以将各种例程放在通用接口后面,而不是将过程指针作为显式参数传递:

interface matvec
  module procedure matvec1, matvec2
end interface

然后,您的solver例程可以只使用带有或不带有额外参数的通用名称。solver当使用 Bálint 建议的将 a 定义为具有类型绑定过程的派生类型的方法时,当然也可以采用相同的方法:

type :: solver
  real, allocatable :: matrix(:,:), v1(:), v2(:)
contains
  procedure, pass :: matvec1
  procedure, pass :: matvec2
  generic :: matvec => matvec1, matvec2
end type

主要区别在于这不使用多态性来确定要调用的正确过程,而是使用虚拟参数的特性。

我不确定您对过程指针的意图;如果您希望在运行时更改其目标(或者可能为其“未定义”状态分配一些特殊含义),那么指针是唯一的方法,并且所有目标都需要匹配相同的抽象接口。相反,如果您只需要根据它们的参数选择几个过程之一,那么您可以利用接口(我的示例)或重载(Bálint 的示例)。类型的每个扩展都可以使用新过程扩展继承的generic绑定,或重载继承的特定绑定。

于 2013-03-08T15:39:20.037 回答