在现代Fortran中,使用模块中的子例程加载派生类型

3

目标:使用子程序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

以下网页尝试了但没有成功: Fortran中模块、子程序和函数的正确使用Fortran 90 - 将值从主子程序传输到函数和其他子程序Fortran: 在另一个模块的过程中调用模块中的函数Fortran 90 如何在模块的子程序中调用一个函数?
2个回答

3
作为 Vladimir F 的评论 所指出的,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 )

本身不是有效的。首先,在调用reflections%...时,必须分配reflections。其次,对于绑定,reflections数组不允许使用nopass

那么这给您带来了什么?嗯,您将不得不修复reflections的可分配性,但可能最简单的方法就是遵循使load_things_sub公共并坚持第一条路径,摆脱类型绑定程序。


好的,你可以这样做:type(su2) :: other_object; call other_object%load_things(nthings, reflections)。但在没有其他信息的情况下,这似乎是无意义的复杂性。考虑到参考资料,我怀疑他们只想直接调用该过程。 - IanH
在所有方面都达成了共识,@IanH。我本来想加强我的最后一段,但是我看到你的答案被编辑成了更简洁的“不要费心”的总结。另一个选择是创建一个容器类型,但对于所提供的场景而言,这也过于复杂了。 - francescalus
@francescalus:你所说的“最简单的事情”确实很简单。疲劳导致了排列编程;感谢你提供的解决方案和敏锐的分析。 - dantopa

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
1
@dantopa 这是一个绑定名称,你必须将其作为类型绑定过程 instance%load_things 调用,否则它是无效的。 - Vladimir F Героям слава
@Vladimir:我的排列已经尝试过了。鉴于这个代码示例,call应该如何具体修改? - dantopa
1
没有其他信息的情况下,您目前的方法,即绑定到该过程,没有意义。如果您只是尝试调用一个过程,那么就直接调用它。如果该过程必须通过绑定引用,则需要向我们解释为什么这样做。 - IanH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接