为什么覆盖参数的名称必须与抽象接口的名称相匹配?

Why do the names of overriding arguments have to match those of the abstract interface?

为什么覆盖过程中的参数名称需要与抽象接口的参数名称相匹配?

我明白这些参数的 TYPEINTENT 等显然需要匹配接口,但编译器为什么要关心我所说的变量?

在下文中,我定义了一个简单的抽象实用程序 class,其中包含一个采用双精度参数的延迟过程 EVAL

!------------------------------------- an abstract utility class !
type, abstract :: func_1d
contains
    procedure(interface_1d),deferred :: eval
end type func_1d

!-------------------------------------------- interface for eval !
abstract interface
function interface_1d(this,data) result(rval)
    import :: func_1d
    class(func_1d), intent(inout) :: this
    real*8        , intent(in)    :: data
    real*8 :: rval
end function interface_1d
end interface

定义覆盖 class 和 EVAL 的实现:

type, extends(func_1d) :: foo
contains
    procedure, pass :: eval => eval_foo
end type foo

function eval_foo(this,another_variable_name) result(rval)
    implicit none
    class(foo), intent(inout) :: this
    real*8, intent(in) :: another_variable_name
    real*8 :: rval

    !! etc

end function eval_foo

我从 gfortran 得到以下错误:

Error: Dummy argument 'another_variable_name' of 'eval' at (1) should be named 'data' as to match the corresponding argument of the overridden procedure

如果我用 DATA 代替 ANOTHER_VARIABLE_NAME,一切都会按预期编译和运行。

但这对我来说似乎很愚蠢。我希望能够多次从 FUNC_1D 继承,在各种情况下每次都被迫调用我的变量 DATA 似乎很荒谬。

我不明白为什么编译器应该对参数的 TYPEINTENT 感兴趣?

详细阐述 High Performance Mark 的评论

I don't know but I suspect that it may be down to Fortran's argument keyword capabilities, which mean that you can call your function like this fun_1d(data=the_data,this=that), that is you can name the arguments in the call rather than rely on position matching.

考虑以下因素

type, extends(func_1d) :: foo
 contains
  procedure, pass :: eval => eval_foo
end type foo

type, extends(func_1d) :: bar
 contains
  procedure, pass :: eval => eval_bar
end type bar

使用带有接口的适当过程定义

real*8 function eval_foo(this,foo_var)
  class(foo), intent(inout) :: this
  real*8, intent(in) :: foo_var
end function

real*8 function eval_bar(this,bar_var)
  class(bar), intent(inout) :: this
  real*8, intent(in) :: bar_var
end function

然后

class(func_1d), allocatable :: baz
allocate (foo_or_bar :: baz)  ! For one of the types foo, bar

哪个参数关键字有意义?

print*, baz%eval(data=s)
print*, baz%eval(foo_var=s)
print*, baz%eval(bar_var=s)

[在某些情况下,这会更加明显,尤其是使用可选的伪参数。]


该标准要求您保留相同的虚拟参数名称(很可能会避免上述问题)。参见 12.4.1 ISO/IEC 1539-1:2010:

12.4.1 Interface and abstract interface

The interface of a procedure determines the forms of reference through which it may be invoked. The procedure’s interface consists of its name, binding label, generic identifiers, characteristics, and the names of its dummy arguments. The characteristics and binding label of a procedure are fixed, but the remainder of the interface may differ in differing contexts, except that for a separate module procedure body (12.6.2.5), the dummy argument names and whether it is recursive shall be the same as in its corresponding separate interface body (12.4.3.2).

这表明使用同一接口的单独过程应具有与该接口相同的虚拟参数名称。 4.5.7.3进一步加强了这一点:

The overriding and overridden type-bound procedures shall satisfy the following conditions.
- [...]
- Dummy arguments that correspond by position shall have the same names and characteristics, except for the type of the passed-object dummy arguments.