将 Fortran 指针作为模块过程传递给子例程

Passing Fortran POINTER to SUBROUTINES as MODULE PROCEDURE

我的第一个问题是,“能否将 POINTER 传递给 INTENT 旁边的子程序?”

尽管使用 INTENT(IN) 或 INTENT(INOUT) 传递 Fortran POINTER 似乎是一种常见的做法,但 Intel for Fortran POINTER 的文档说(https://software.intel.com/content/www/us/en/develop/documentation/fortran-compiler-developer-guide-and-reference/top/language-reference/a-to-z-reference/o-to-p/pointer-fortran.html)

The pointer cannot be declared with the INTENT or PARAMETER attributes

这让我很困惑。

我的第二个问题与以下代码有关。

我尝试用 write_matrix_2d 重载 write_matrix - 用于二维数组 - 和 write_matrix_2d_ptr - 用于二维 Fortran 指针。

原来代码无法通过

编译
Ambiguous generic interface WRITE_MATRIX: previously declared specific procedure WRITE_MATRIX_2D is not distinguishable from this declaration. [WRITE_MATRIX_2D_PTR]

如果我评论 (1) 然后它符合要求,并且运行良好(但我认为这是不好的做法,因为 POINTER 参数进入需要数组输入的子程序 write_matrix_2d。)

有没有办法像 C/C++ 一样仅通过参数的数据类型来重载 Fortran 子例程?

module mod_write

    implicit none

    interface write_matrix
        module procedure write_matrix_2d
(1)     !module procedure write_matrix_2d_ptr
    end interface

contains

    subroutine write_matrix_2d(a)

        implicit none
        real, intent(in) :: a(:,:)
  
        ! local variables
        integer :: i, j

        print *, "in ARRAY printing subroutine"
        do i = lbound(a,1), ubound(a,1)
            write(*,*) ( a(i,j), j = lbound(a,2), ubound(a,2) )
        enddo
  
    end subroutine

    subroutine write_matrix_2d_ptr(a)

        implicit none
        real, pointer, intent(in) :: a(:,:)
  
        ! local variables
        integer :: i, j

        print *, "in POINTER printing subroutine"
        do i = lbound(a,1), ubound(a,1)
            write(*,*) ( a(i,j), j = lbound(a,2), ubound(a,2) )
        enddo
  
    end subroutine

end module

program test

    use mod_write

    implicit none

    real, dimension(9)            :: b = (/21, 22, 23, 24, 25, 26, 27, 28, 29/)
    real, dimension(3,3)          :: c
    real, dimension(3,3), target  :: ct(3,3)
    real, dimension(:,:), pointer :: cptr(:,:)

    c = reshape( b, (/3, 3/) )

    write(*,*)
    write(*,*) 'c'
    call write_matrix(c)
(2) !call write_matrix_2d(c)

    ct = c
    cptr => ct(2:3,2:3)

    write(*,*)
    write(*,*) 'ct'
    call write_matrix(ct)
(2,3)!call write_matrix_2d_ptr(ct)

    write(*,*) 'cptr'
    call write_matrix(cptr)
(2) !call write_matrix_2d_ptr(cptr)

end program

我的第三个问题又和附上的代码有关。重载不是什么大问题,因为我可以在代码中单独使用 write_matrix_2dwrite_matrix_2d_ptr 作为 (2)。但是,正如您在 (3) 看到的那样,call write_matrix_2d_ptr(ct) 使用 target 输入 ct 运行良好,而 write_matrix_2d_ptr 需要 pointer 输入。这样可以吗,还是我应该再做一个 write_matrix_2d_target

谢谢。

(1) 意图限制是一些复制和粘贴错误,或者是在一些我不明白的奇怪上下文中。 Fortran 90中就有这样的重写

(2) “但我认为这是不好的做法,因为 POINTER 参数进入需要数组输入的子程序 write_matrix_2d。”

将 Fortran 指针变量作为普通变量传递没有什么不好。默认的参数传递机制是使用正常的 non-ointer 机制传递指针的目标。只有在有特定理由的情况下,才会使用 pinter 虚拟参数。大多数情况下,tbat 意味着比一个在子例程中使用关联状态。还有一些其他用途,但你需要一个特定的理由来将你的参数声明为指针,否则它只会使事情复杂化。

(3) target 可以传递给 Fortran 2008 中的 pointer, intent(in)

编译器文档有误(或严重过时)。作为指针的虚拟参数也可以具有 intent 属性。该属性适用于参数的指针关联状态,而不是目标。

如果伪参数可区分,则可以重载通用接口中的过程。如果虚拟参数具有不同的类型、种类或级别,则它们是可区分的。某物是否是指针不是其类型的一部分。 (为了完整起见,如果一个参数是没有 intent(in) 的指针,而另一个是可分配的,那么参数也是可区分的。)通用接口中不同过程的可区分伪参数的要求意味着特定通用过程所围绕的规则参考解析为非常简单。

您的重载示例将是模棱两可的 - 将(n 关联的)指针实际参数传递给 non-pointer 虚拟参数是可以的 - 实际参数指定指针的目标。还允许将具有目标属性的 non-pointer 实际值传递给 intent(in) 指针虚拟对象。

是否为指针与是否为数组完全正交。

Fortran 中的指针主要用于在程序执行期间引用不同的事物(目标)。

如果您需要在与指针的关联状态相关的过程中执行某些操作,则伪参数只需要是一个指针 - 也许您想要测试关联状态,或者将指针与其他东西相关联。