【问题标题】:gfortran pointer procedure type issuegfortran 指针过程类型问题
【发布时间】:2018-05-16 11:29:11
【问题描述】:

我尝试创建一个无需使用通用过程即可接受不同输入类型的过程。实际上,(在这种情况下)我更喜欢手动设置过程指针的目标来定义要使用的过程,而不是通用过程。

这就是我对以下几乎最小的示例所做的。

module mo
implicit none

type :: TypeB
    character(len=5) :: info='Hello'
    contains
    procedure,  pass(fd) :: say_hello 
end type TypeB

type :: TypeA
    character(len=4) :: txt='Hola'
    !type(TypeB) :: Tb
end type TypeA

type, extends(TypeA) :: TypeC
    character(len=4) :: tt='Hey!'
    type(TypeB) :: Tb
end type TypeC

type, extends(TypeA) :: TypeD
    character(len=3) :: tt='Ho!'
    character(len=3) :: ti='you'
    !type(TypeB) :: Tb
end type TypeD

type(TypeC) :: Tc
type(TypeD) :: Td
procedure(), pointer :: proc
class(TypeA), allocatable :: CA


contains

subroutine say_hello(fd)
    implicit none
    ! type(TypeB), intent(inout) :: fd
    class(TypeB), intent(inout) :: fd

    print *, fd%info

end subroutine say_hello

subroutine procC(fd, args)
    implicit none
    ! class(TypeC), intent(inout) :: fd
    type(TypeC), intent(inout) :: fd
    real :: args

    print*, args
    print*, fd%tt
    call fd%Tb%say_hello()
end subroutine procC

subroutine procD(fd, args)
    implicit none
    ! class(TypeD), intent(inout) :: fd
    type(TypeD), intent(inout) :: fd
    ! class(TypeA), intent(inout) :: fd
    real :: args

    print*, args
    print*, fd%tt
    print*, fd%ti
end subroutine procD

end module mo


program p
    use mo
    implicit none

    print* , 'START'
    print *, Tc%tb%info
    print *, Tc%txt
    call Tc%Tb%say_hello()
    call procC(Tc, 1.0)
    call procD(Td, 2.0)
    print*, 'OK'

    allocate(TypeD :: CA)
    proc =>procD
    call proc(CA, 3.0)
    deallocate(CA)

    allocate(TypeC :: CA)
    proc =>procC
    call proc(CA, 4.0)
    deallocate(CA)

    print*, 'END'

end program p

当我在 Linux 上使用 ifort 编译时,我得到了预期的结果,但是当我在 Windows 或 Linux(gfortran 5.5.0 和 6.4.0)上使用 gfortran (MinGW 6.2.0) 编译时,我得到了一些奇怪的结果:

START
Hello
Hola
Hello
1.00000000
Hey!
Hello
2.00000000
Ho!
you
OK
3.00000000

@R
4.00000000

ÇR@
END

当我在我的大程序中使用这种方法时,情况变得更糟了。

那么,有没有办法避免这些问题呢?这是gfortran的错误吗?还是我误会了什么?

【问题讨论】:

    标签: fortran gfortran


    【解决方案1】:

    你的程序有问题。

    考虑部分

    proc =>procD
    call proc(CA, 3.0)
    

    我首先考虑的是

    call procD(CA,3.0)
    

    子程序procD 的第一个虚拟参数声明为type(typeD)。这是一个非多态实体,具有动态和声明类型typeD。主程序的实际参数CA是动态类型typeD但声明类型为typeA的多态实体。

    在过程引用中,每个虚拟参数的类型都必须与其关联的实际参数类型兼容。这不是这里的情况:非多态对象的类型仅与与自身声明类型相同的实体类型兼容。它与具有相同动态类型但声明类型不同的多态实体类型不兼容。

    在工作版本中

    call procD(Td, 2.0)
    

    实际参数Td 是声明类型typeD,因此是类型兼容的。

    在此处使用带有隐式接口的过程指针会使编译器更难在您的程序中检测到此错误(这不是必需的)。

    【讨论】:

    • 如果我理解的很好,我应该把子程序procD中的type(typeD)改成class(typeD),得到一个多态参数。但是我这样做了,程序指针proc 会询问一个接口。并且接口将需要使用class(TypeA) 作为父多态参数,因此我将无法根据情况调用嵌入在TypeCTypeD 中的对象,因为这些对象是TypeA 的一部分。所以没有真正的解决方案来做我想做的事?
    • 这种复杂性是我避免使用“这就是你应该做的......”声明来总结的原因。做事的最佳方式将取决于您的完整设计目标,但重新考虑避免使用泛型将是我的第一个建议。您还可以选择包含中间非多态事物的包装器。
    • 这就是我害怕的。除了我不确定完全理解您关于“带有中间非多态事物的包装器”的观点。你能准确地说一下你的想法吗?
    • 经过反思(感谢您的提问!),我部分形成的包装想法很糟糕。可能还有其他类似的想法,但我最好不要解释它,直到我仔细考虑它。 [或者其他人可以。]
    • 虽然不确定,但是在将虚拟“fd”的声明更改为 class(TypeA) 并将 proc 更改为“procedure( procC), 指针 :: proc"?
    猜你喜欢
    • 2011-07-27
    • 2013-03-26
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    相关资源
    最近更新 更多