我可以在Fortran中模仿多个传递对象的伪参数吗? [英] Can I mimic multiple passed-object dummy arguments in 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).
我尝试过使用一个单独的传递对象参数,该参数同时包含foo
和bar
,例如作为数组或指针,但这是标准所禁止的.
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屋!