我可以在 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)
?
推荐答案
你可以通过两次使用single dispatch来做到这一点:
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屋!