Fortran:从函数的返回类型访问值
我已经创建了一个派生类型V,并包含了一个add函数 这样我就可以使用运算符+ 但是当我这样做的时候Fortran:从函数的返回类型访问值,fortran,operator-overloading,Fortran,Operator Overloading,我已经创建了一个派生类型V,并包含了一个add函数 这样我就可以使用运算符+ 但是当我这样做的时候 z = u + v Call vsum(z, u, v) 不执行该操作。我想这是因为z%kn 未被访问 但是当我这样做的时候 z = u + v Call vsum(z, u, v) 一切正常 下面是派生类型和 重载函数vadd Module vtest Type :: V Character (Len=8) :: kn Real, Allocatable :: vc(:
z = u + v
Call vsum(z, u, v)
不执行该操作。我想这是因为z%kn
未被访问
但是当我这样做的时候
z = u + v
Call vsum(z, u, v)
一切正常
下面是派生类型和
重载函数vadd
Module vtest
Type :: V
Character (Len=8) :: kn
Real, Allocatable :: vc(:)
Contains
Procedure :: vadd
Generic :: Operator (+) => vadd
End Type vtest
Contains
Function vadd (b, c) Result (a)
Type (V) :: a
Class (V), Intent (In) :: b, c
!!$ In vsum, use is made of a% kn
Call vsum (a, b, c)
End Function vadd
Subroutine vsum (ta, tb, tc)
Type (V), Intent (InOut) :: ta
Type (V), Intent (In) :: tb, tc
Logical :: la, lb, lc
la = .False.; lb = .False.; lc = .False.
Select Case (ta%kn)
Case ("Real32")
If (Allocated (ta%vc)) la = .True.
If (Allocated (tb%vc)) lb = .True.
If (Allocated (tc%vc)) lc = .True.
If (la .And. lb .And. lc) Then
ta%vc = tb%vc + tc%vc
End If
End Select
End Subroutine vsum
End Module vtest
Program test
Use vtest
Type (V) :: z
z% kn = "Real32"
Allocate (z% vc_real32(3))
Write (*,*) "z = u + v"
Write (*,*) "z% kn: ", z% kn
z = u + v
Write (*,*) "z% kn: ", z% kn
Write (*,*) "z: ", z% vc_real32
End Program vtest
让我们看看子程序
vsum
。在该子例程中完成的工作取决于所有三个对象的组件定义ta
、tb
和tc
。为使求和按预期进行,必须分配所有可分配组件,并使ta%kn
与'Real32'
匹配
没有完整的工作示例,但正如您所说,当有一个像
call vsum(z, u, w) ! V is the name of the type, so call the variable w
z%kn
设置为'Real32'
但是,使用定义的操作
z = u + w
有一个函数引用
z = vadd(u, w)
电话在哪
call vsum (a, b, c) ! Actual arguments "z", u, w.
现在,a
是vadd
的函数结果。这样做的结果是,就像带有intent(out)
a
的伪参数一样,最初是未定义的
这基本上意味着,当通过
vadd
z
时,它将使用未定义的组件kn
和未分配的组件vc
到达vsum
。因此,总和的要求没有得到满足(事实上,select case
构成了无效的引用)
我想我也可以评论一下如何解决这个问题 在
vsum
中,实际上是从“结果”中获取操作类型。相反,类似于
Subroutine vsum (ta, tb, tc)
Type (V), Intent (Out) :: ta
Type (V), Intent (In) :: tb, tc
Logical :: lb, lc
lb = .False.; lc = .False.
! In here we probably want some consistency checking...
Select Case (tb%kn)
Case ("Real32")
If (Allocated (tb%vc)) lb = .True.
If (Allocated (tc%vc)) lc = .True.
If (lb .And. lc) Then
ta%vc = tb%vc + tc%vc ! ta%vc being automatically allocated
End If
End Select
End Subroutine vsum
当然,这并不能满足您(从标题中)从结果中获取操作类型的愿望。您可以使用原始的子例程方法来实现这一点,但有一种情况除外,那不是Fortran函数的原理
如果要使用已定义的操作,则不能在赋值的左侧定义该操作。在表达式u+w
中,没有左侧,但定义的操作仍应正常运行。也就是说,在声明中
z = u + w
您不是说“
z
是应用于u
和w
的操作的结果”。但是:“计算应用于u
和w
的操作+
,并将结果(通过定义或隐式赋值)分配给z
”。在到达“结果类型”之前,存在该赋值。这就是为什么我在前面将z
作为实际参数放在引号中的原因。请显示vsum
的代码。代码仍然不完整。几乎没有一个mcve它缺少操作符调用及其周围环境。在您未显示的任何细节中都可能存在错误。您应该准备一个完全可编译的代码。包括代码的输出。您是如何诊断未执行该操作的?发生了什么,而不是?+1,尤其是最后一段。Fortran函数从不“查看”作业左侧的内容。他们根本不需要被安排在任务中!它们计算了一些表达式,而调用代码不知怎么地使用了该表达式。这意味着,本质上,当通过vadd z时,它将使用未定义的组件kn和未分配的组件vc传递给vsum。因此,总和的要求没有得到满足(事实上,select案例构成了一个无效的引用)这就是正在发生的事情。我已经尝试了你的修改,但是我仍然没有得到正确返回的结果。在函数“vadd”中调用“vsum”后打印了数组值,得到了正确的值。但是,在主程序中,输出的结果仍然未定义。您的意思是,在调用vadd
之后,a
具有正确的值,但这些值随后不会传递到z
?这对我来说没有多大意义,但我确实看到您的主程序并不完全正确:右侧变量没有定义(其中一个仍然命名不正确)。