【问题标题】:Loading derived types with a subroutine within a module in modern Fortran在现代 Fortran 的模块中使用子例程加载派生类型
【发布时间】:2015-11-18 10:19:21
【问题描述】:

目标:使用子程序load_things 加载su2 类型的结构库。

运行gfortran simple.f90 产生

Undefined symbols for architecture x86_64:
  "_load_things_", referenced from:
      _MAIN__ in cc7DuxGQ.o
      (maybe you meant: ___myclass_MOD_load_things_sub)
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

主程序如下:

program simple
  use myClass
  implicit none
  integer :: nThings
  type ( su2 ) :: reflections
      call load_things ( nThings, reflections )
end program simple

模块定义为:

module myClass
implicit none
type :: su2
    integer :: matrix_obj ( 1 : 2, 1 : 2 )
contains
    private
    procedure, nopass, public :: load_things => load_things_sub
end type su2

private load_things_sub
contains
    subroutine load_things_sub ( nThings, U )
        integer,      intent ( out ) :: nThings
        type ( su2 ), intent ( out ), allocatable :: U ( : )
            nThings = 2
            allocate ( U ( nThings ) )
            U ( 1 ) % matrix_obj = reshape ( [ 0, 1, 1, 0 ], [ 2, 2 ] )
            U ( 2 ) % matrix_obj = reshape ( [ 0, 1, 1, 0 ], [ 2, 2 ] )
    end subroutine load_things_sub

end module myClass

研究了以下网页,没有成功:Correct use of modules, subroutines and functions in fortran

Fortran 90 - to transmit values from main subroutine to the functions and other subroutines,

Fortran: Calling a function in a module from a procedure in another module,

Fortran 90 How to call a function in a subroutine in a module?

【问题讨论】:

    标签: module fortran gfortran subroutine


    【解决方案1】:

    因为Vladimir F comments load_things 是派生类型reflections 的绑定名称。正如答案所说,它不是子例程的名称。

    那么,IanH 说,您可以将代码更改为

    call load_things_sub ( nThings, reflections )
    

    但您还需要将其设为模块的公共实体。您可能希望使用类型绑定的方式,以便它可以保持私有(类型本身的绑定是可访问的):

    call reflections%load_things(nThings, reflections)
    

    这带来了另一组观点:你不能做到以上。

    您使用nopass 进行绑定,因为该类型的虚拟参数是一个可分配数组:您不能使用pass。但是,在您的主程序中,虚拟参数 reflections 是不可分配的标量:那里不匹配,因此 call load_things_sub(nThings, reflections) 无效。

    进一步

    type ( su2 ), allocatable :: reflections(:)
    call reflections%load_things ( nThings, reflections )
    

    本身无效。首先,对于call reflections%...,必须分配reflections。其次,reflections 不允许绑定数组 nopass

    这会让你在哪里?好吧,您必须修复 reflections 的可分配性,但最简单的做法可能是继续将 load_things_sub 设为 public 并坚持第一条路径,摆脱类型绑定过程。

    【讨论】:

    • 好吧,你可以做类似type(su2) :: other_object; call other_object%load_things(nthings, reflections) 的事情,但是在没有来自 OP 的其他信息的情况下,这似乎是毫无意义的复杂性。鉴于引用我怀疑他们只想直接调用该过程。
    • 同意所有观点,@IanH。我打算加强我的最后一段,但我看到你的答案被编辑为对“不要打扰”的更简洁的总结。另一种选择是创建一个容器类型,但这对于所呈现的场景来说又过于复杂了。
    • @francescalus:您的“最容易做的事情”非常简单。疲劳通过排列诱导编程;感谢您的解决方案和敏锐的分析。
    【解决方案2】:

    您的模块没有名为 load_things 的子例程 - 它有一个名为 load_things_sub 的子例程。选择正确的名称变体,然后适当地更正其他语句中的名称。

    在最初提交此答案之后,OP 向模块添加了一条私有语句,使 load_things_sub 在使用该模块的范围内无法访问。在没有其他信息的情况下,应该删除私人声明。

    通过绑定引用诸如load_thing_sub 之类的过程几乎没有意义。只需将其作为正常程序引用即可。

    请注意,列出的许多参考资料都是针对 Fortran 90 的。绑定是在 Fortran 2003 中引入的。

    【讨论】:

    • procedure, nopass, public :: load_things => load_things_sub 应提供公共名称load_things
    • @dantopa 这是一个绑定名称,你必须把它称为类型绑定过程instance%load_things,否则它是无效的。
    • @Vladimir:我的排列已经尝试过了。鉴于此代码示例,应该如何具体修改 call
    • 如果没有其他信息,您当前的方法(您绑定到该过程)是没有意义的。如果您只是想调用一个过程,那么只需调用该过程。如果必须通过绑定来引用该过程,那么您需要向我们解释为什么会这样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    • 2019-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多