我可以在Fortran中模仿多个传递对象的伪参数吗? [英] Can I mimic multiple passed-object dummy arguments in Fortran?

查看:150
本文介绍了我可以在Fortran中模仿多个传递对象的伪参数吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个过程,它接受两个传递对象的伪参数,例如

I would like to write a procedure which takes two passed-object dummy arguments, such as

module m
  type, abstract :: Parent
  contains
    procedure(f_Parent), deferred :: f
  end type

  abstract interface
    subroutine f_Parent(foo,bar)
      import Parent
      implicit none
      class(Parent), intent(in) :: foo
      class(Parent), intent(in) :: bar
    end subroutine
  end interface

  type, extends(Parent) :: Child
  contains
    procedure, public :: f => f_Child
  end type
contains
  subroutine f_Child(foo,bar)
    implicit none
    class(Child), intent(in) :: foo
    class(Child), intent(in) :: bar
  end subroutine
end module

但这是Fortran标准所不允许的,因为bar不是传递对象的伪参数,因此必须为class(Parent)而不是class(Child).

but this is not allowed by the Fortran standard, as bar is not a passed-object dummy argument, and so must be class(Parent) and not class(Child).

我当前的解决方案是

subroutine f_Child(foo,bar)
  implicit none
  class(Child),  intent(in) :: foo
  class(Parent), intent(in) :: bar

  select type(bar); type is(Child) 
  end select
end subroutine

可以,但是select type构造太慢,并且支配着我的代码的运行时(该子例程被多次调用).

which works, but the select type construct is too slow, and dominates the runtime of my code (this subroutine is called many times).

我尝试过使用一个单独的传递对象参数,该参数同时包含foobar,例如作为数组或指针,但这是标准所禁止的.

I have tried having a single passed-object argument which holds both foo and bar, e.g. as an array or pointer, but this is also forbidden by the standard.

是否有任何方法可以模仿具有多个传递对象伪参数的行为,而这又不会增加select type构造的成本?还是从class(Parent)获取class(Child)参数的更快方法?

Is there any way of mimicking the behaviour of having multiple passed-object dummy arguments which does not incur the cost of a select type construct? Or maybe a faster way of getting an argument of class(Child) from class(Parent)?

推荐答案

您可以通过两次使用一次调度来做到这一点:

You can do it by using single dispatch twice:

Module m

  Implicit None

  Type, Public, Abstract :: Parent
   Contains
     Procedure( i_Parent_Parent ),              Public , Deferred :: f
     Procedure( i_Child_Parent  ), Pass( bar ), Private, Deferred :: f_c_p
     Procedure( i_set           ),              Public , Deferred :: set
  End Type Parent

  Type, Public, Extends( Parent ) :: Child
     Integer               , Private :: data
   Contains
     Procedure             , Public  :: f     => f_Child_Parent
     Procedure, Pass( bar ), Private :: f_c_p => f_Child_Child
     Procedure             , Public  :: set   => f_Child_set
  End Type Child

  Private

  Abstract Interface
     Subroutine i_Parent_Parent( foo, bar )
       Import :: Parent
       Implicit None
       Class( Parent ), Intent( In ) :: foo
       Class( Parent ), Intent( In ) :: bar
     End Subroutine i_Parent_Parent
     Subroutine i_Child_Parent( foo, bar )
       Import :: Parent, Child
       Implicit None
       Class( Child  ), Intent( In ) :: foo
       Class( Parent ), Intent( In ) :: bar
     End Subroutine i_Child_Parent
     Subroutine i_set( foo, data )
       Import :: Parent
       Class( Parent ), Intent( InOut ) :: foo
       Integer        , Intent( In    ) :: data
     End Subroutine i_set
  End Interface

Contains

  Subroutine f_Child_Parent( foo, bar )
    Implicit None
    Class( Child  ), Intent( In ) :: foo
    Class( Parent ), Intent( In ) :: bar
    Call bar%f_c_p( foo )
  End Subroutine f_Child_Parent

  Subroutine f_Child_Child( foo, bar )
    Implicit None
    Class( Child ), Intent( In ) :: foo
    Class( Child ), Intent( In ) :: bar
    Write( *, * ) 'In child child foo%data = ', foo%data, ' bar%data = ', bar%data
  End Subroutine f_Child_Child

  Subroutine f_Child_set( foo, data )
    Implicit None
    Class( Child ), Intent( InOut ) :: foo
    Integer       , Intent( In    ) :: data
    foo%data = data
  End Subroutine f_Child_set

End Module m

Program driver

  Use m, Only : Parent, Child

  Class( Parent ), Allocatable :: foo, bar

  Allocate( Child :: foo )
  Allocate( Child :: bar )

  Call foo%set( 3 )
  Call bar%set( 4 )

  Call foo%f( bar )

End Program driver
ian@eris:~/work/stack$ gfortran-8 -std=f2008  -fcheck=all -Wall -Wextra dd.f90
ian@eris:~/work/stack$ ./a.out
 In child child foo%data =            3  bar%data =            4
ian@eris:~/work/stack$ 

这是否快于select type将取决于实现,但我认为它更干净.

Whether this is quicker than select type will be implementation dependent, but I think it is cleaner.

这篇关于我可以在Fortran中模仿多个传递对象的伪参数吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆