在 Fortran 中选择 class 中的过程

Selecting procedures within a class in Fortran

我们如何select程序内类?编译错误为:

$ gfortran  -Wall -Wextra -Wconversion -Og -pedantic -fcheck=bounds -fbacktrace -g  -fmax-errors=5 driver.f08 
driver.f08:60:39:

         call sub ( me, myMeasurements )
                                       1
Error: More actual than formal arguments in procedure call at (1)

发生在 subroutine local_selector_sub(第 48 行)中 module mIntermediates(第 28 行)。参数 sub 将是 compute_intermediates_dotcompute_intermediates_sum.

MWE 代码 driver.f08 尝试 select 计算路径。调用两个选项 compute_intermediates_sumcompute_intermediates_dot 都有效(第 93、94 行)。

问题是对 local_selector(第 95 行)的调用,其中包含目标计算路径的名称。目标是有不同的表现形式,例如

call myIntermediates % local_selector( compute_intermediates_sum, myMeasurements )

call myIntermediates % local_selector( compute_intermediates_dot, myMeasurements )

MWE:

module mMeasurements  !   *   *   *

    implicit none
    integer, parameter :: m = 2

    type :: measurements
        real, dimension ( 1 : m ) :: x = 0.0, y = 0.0, ones = 1.0, residuals = 0.0
    contains
        private
        procedure, public :: load_data
    end type measurements

contains

    subroutine load_data ( me )

        class ( measurements ), target :: me

            me % x ( 1 ) = 1.0 !           load data
            me % x ( 2 ) = 2.0
            me % y ( 1 ) = 15.6
            me % y ( 2 ) = 17.5

    end subroutine load_data

end module mMeasurements

module mIntermediatesDefinitions  !   *   *   *

    use mMeasurements
    implicit none

    type :: intermediates
        real :: sxy = 0.0
    contains
        private
        procedure, public :: compute_intermediates_dot => compute_intermediates_dot_sub
        procedure, public :: compute_intermediates_sum => compute_intermediates_sum_sub
        procedure, public :: local_selector            => local_selector_sub
    end type intermediates

    private :: local_selector_sub
    private :: compute_intermediates_dot_sub
    private :: compute_intermediates_sum_sub

contains

    subroutine local_selector_sub ( me, sub, myMeasurements )  ! problematic routine

        class ( intermediates ), target      :: me
        type ( measurements ), intent ( in ) :: myMeasurements

        interface mySub
            subroutine sub
                use mMeasurements
                import intermediates
            end subroutine sub
        end interface mySub

        call sub ( me, myMeasurements )

    end subroutine local_selector_sub

    subroutine compute_intermediates_dot_sub ( me, myMeasurements )

        class ( intermediates ), target      :: me
        type ( measurements ), intent ( in ) :: myMeasurements

            me % sxy = dot_product ( myMeasurements % x,    myMeasurements % y )

    end subroutine compute_intermediates_dot_sub

    subroutine compute_intermediates_sum_sub ( me, myMeasurements )

        class ( intermediates ), target      :: me
        type ( measurements ), intent ( in ) :: myMeasurements

            me % sxy = sum ( myMeasurements % x * myMeasurements % y )

    end subroutine compute_intermediates_sum_sub

end module mIntermediatesDefinitions

program driver  !   #   #   #

    use mMeasurements
    use mIntermediatesDefinitions

    implicit none
    type ( measurements )  :: myMeasurements
    type ( intermediates ) :: myIntermediates

        call myIntermediates % compute_intermediates_dot ( myMeasurements )
        call myIntermediates % compute_intermediates_sum ( myMeasurements )
        call myIntermediates % local_selector            ( compute_intermediates_dot, myMeasurements )

end program driver

版本: GNU Fortran (GCC) 5.1.0

子程序 local_selector_sub 中的虚拟过程 sub 具有由接口块提供的接口。那个界面

interface
  subroutine sub
  end subroutine sub
end interface

(删除了多余的 useimport 以及未使用的通用名称)表示 sub 没有参数。在下面的调用中,您试图给它两个参数,而编译器对此有正确的抱怨。

要解决此问题,您需要正确指定接口(或依赖隐式接口)。正如我所注意到的,compute_intermediates_dot_subcompute_intermediates_sum_sub 这两个选项具有您可以编写的相同特征,例如

subroutine local_selector_sub ( me, sub, myMeasurements )  ! problematic routine
  class ( intermediates ), target          :: me
  type ( measurements ), intent ( in )     :: myMeasurements
  procedure(compute_intermediates_dot_sub)    sub

  call sub ( me, myMeasurements )

end subroutine

(或者您可以创建一个中性命名的抽象接口或使用适当的接口块)。

但这会导致一个更有趣的问题:

call myIntermediates%local_selector(compute_intermediates_dot, myMeasurements)

compute_intermediates_dot 不是子例程。它是 intermediates.

类型绑定过程的绑定名称

如果您希望将子例程传递给 myIntermediates%local_selector,最简单的解决方案是使子例程 compute_intermediates_dot_sub 本身成为 accessible/public 并传递它。但我很想坚持在其他两条线之间进行选择。

或者,如果您确实希望 select 将子例程传递给 myIntermediates%local_selector,那么您可以考虑使用过程指针组件而不是类型绑定过程。