接口中数组的形状是否可以匹配多个固定数组大小?

Can the shape of an array in an interface match multiple fixed array size?

我有多个带有参数 p 的子例程,它是一个明确大小的数组,如

subroutine foo(p)
integer,dimension(2),intent(in) ::p
end subroutine foo

subroutine bar(p)
integer,dimension(3),intent(in) ::p
end subroutine bar

我想通过间接调用来调用这两个函数,但找不到一种方法来声明与 foo 和 bar 签名都匹配的接口...

例如,在界面中使用假定的数组大小是行不通的:

subroutine indirect(f,p)
integer,dimension(*),intent(in):p
interface
  subroutine f(p)
  integer,dimension(*),intent(in) :: p
  end subroutine f
end interface
call f(p)
end subroutine indirect

当我间接调用 foo 或 bar 时,编译器 (gfortran 4.9.2) 抱怨 f 的第一个参数 p 的形状不匹配...

integer,dimension(2) :: pfoo
integer,dimension(3) :: pbar

pfoo = (/ 0,1 /)
pbar = (/ 1,2,3 /)

call foo(pfoo) ! direct call is OK
call bar(pbar)

call indirect(foo,pfoo) ! compiler complains about foo signature
call indirect(bar,pbar) ! same for bar...

编译器错误类似于:

Error: Interface mismatch in dummy procedure 'f' at (1): Shape mismatch in dimension 1 of argument 'p'

当然,我可以修改 foo 和 bar 签名以使用假定的数组大小 (*) 而不是固定的数组大小,但是

  1. 就好像我为了制作编译器而丢失了一些信息 不增加任何安全措施就很开心

  2. foo 和 bar 不是我的代码,我不想更改它们...

我找到了一个解决方法,但它包括为每个子例程 foo 和 bar 编写一个假定大小的包装器

call indirect(foo_wrapper,pfoo) ! compiler complains about foo signature
call indirect(bar_wrapper,pbar) ! same for bar...

subroutine foo_wrapper(p)
integer,dimension(*),intent(in) ::p
call foo(p)
end subroutine foo_wrapper

subroutine bar_wrapper(p)
integer,dimension(*),intent(in) ::p
call bar(p)
end subroutine bar_wrapper

或者最终,用间接和包装器中的延迟大小替换所有假定大小,以便有机会进行运行时检查,这也有效,但这不是重点...

关键是,因为我有很多这样的 foo/bar 没有办法正确声明接口(我的意思是没有包装器或其他人工制品)。

我无法破译标准(我使用了 http://www.j3-fortran.org/doc/year/10/10-007.pdf - 我假设它在 12.5.2.9 与虚拟过程实体相关的实际参数 §2 左右),所以不知道是不是gfortran的限制。现在我没有任何其他可用的编译器,但我想知道是否有其他编译器可以编译(英特尔? - 我在 windows 7 64 位)。

我会看看 gfortran 的投诉是否正确,无论如何,有哪些选项可以解决投诉。参考是 Fortran 2008。

12.5.2.9确实很重要

  1. If the interface of a dummy procedure is explicit, its characteristics as a procedure (12.3.1) shall be the same as those of its effective argument, except that [inapplicable things]

f in indirect 是一个带有显式接口的虚拟过程(通过接口块;12.4.2.1)。查看参考12.3.1我们看到

The characteristics of a procedure are .. , the characteristics of its dummy arguments, ..

foobarf 都是带有单个伪参数的过程(碰巧都称为 p)。所以,如果 foo 想成为与 f 相关的有效参数,那么 foop 必须匹配 fp 的特征].每个 p 都是一个虚拟数据对象,因此 12.3.2.2 变得相关:

The characteristics of a dummy data object are its type, its type parameters (if any), its shape, ... If a shape, size, or type parameter is assumed or deferred, it is a characteristic.

我们发现类型和类型参数匹配。但是,f 中的 p 具有假定的大小。 foo中的p没有这个匹配特征。然后,不允许在对 indirect 的调用中将 foof 相关联。 bar.

也是如此

这种要求dummy data对象的匹配特征必须具有相同的形状,自然而然会得出另外一个结论:foobar不具备作为过程的匹配特征。对于第三个程序来匹配两者的形状特征必须被忽略。

可以使用包装器子例程,但我也会考虑是否可以更改各种子例程以采用假定形状参数。这比假定大小要好得多。但是,正如您所说,我也不愿意更改该代码。

对于子例程foobar,因为您有它们,还有另一个可用的选项。这些子例程不需要调用者为它们提供显式接口 (12.4.2.2)。因此,在 indirect 中,您可以只废弃接口块:有关匹配的规则要宽松得多(12.5.2.9 的其他部分)。但是,对于其他程序,这可能是不可能的。

综上所述,ifort 似乎可以愉快地编译并且 运行 您拥有的代码...