【问题标题】:Breaking up a Module into Multiple Files in Fortran在 Fortran 中将一个模块分解为多个文件
【发布时间】:2018-07-13 11:47:00
【问题描述】:

我正在尝试在不同的派生类型之间添加转换函数。我是 希望它们成为返回另一个派生类型的第一个派生类型的函数。只要它们在同一个文件和模块中,这没有问题。但我真的希望它们能够被分成多个文件,否则它将是一个非常大的文件。由于依赖关系以及 Fortran 中缺少命名空间,我无法弄清楚如何执行此操作。

有没有办法做到这一点?

这是我希望将其分成两个文件(每个派生类型一个)的示例。

Module ConversionStuff
  implicit none

  type A_T
    real :: a, b, c
  contains
    procedure :: toX => a_toX
  end type A_T

  type X_T
    real :: x, y, z
  contains
    procedure :: toA => x_toA
  end type X_T

  contains

  function a_toX(this) result(x)

     class(A_T), intent(inout) :: this
     type(X_T) :: x

     x%x = this%a * 2
     x%y = this%b * 2
     x%z = this%c * 2

  end function a_toX

  function x_toA(this) result(a)

     class(X_T), intent(inout) :: this
     type(A_T) :: a

     a%a = this%x * 0.5
     a%b = this%y * 0.5
     a%c = this%z * 0.5

  end function x_toA

End Module ConversionStuff

如果有错别字,我深表歉意。我没有在这台计算机上编译 Fortran 的简单方法。

【问题讨论】:

  • 你知道子模块吗?
  • 我是;但是,我还没有使用具有该功能的编译器(希望很快)。不过,我没想到会解决这个问题。我可能错误地假设子模块仍将单独编译,因此留下循环依赖
  • 我不是问,因为我认为他们解决了你的问题,而是想看看你是否已经排除了他们。 (如果你有没有必要进一步思考。)
  • 我没有排除它,但我认为它不会解决问题。

标签: class module namespaces fortran


【解决方案1】:

在当前的语言中,这很容易通过子模块来处理——两个类型定义都与“共享”独立模块过程的接口一起进入祖先模块,然后过程定义在子模块之间根据需要进行拆分。

MODULE ConversionStuff
  IMPLICIT NONE
  TYPE :: A_T
    REAL :: a, b, c
  CONTAINS
    PROCEDURE :: toX => a_toX
  END TYPE A_T
  TYPE :: X_T
    REAL :: x, y, z
  CONTAINS
    PROCEDURE :: toA => x_toA
  END TYPE x, y, z
  INTERFACE
    MODULE FUNCTION a_toX(this) RESULT(x)
      IMPLICIT NONE
      CLASS(A_T), INTENT(IN) :: this
      TYPE(X_T) :: x
    END FUNCTION a_toX
    MODULE FUNCTION x_toA(this) RESULT(a)
      IMPLICIT NONE
      CLASS(X_T), INTENT(IN) :: this
      TYPE(A_T) :: a
    END FUNCTION x_toA
  END INTERFACE
END MODULE ConversionStuff

SUBMODULE (ConversionStuff) Procedures_for_X
  IMPLICIT NONE
CONTAINS
  MODULE PROCEDURE a_toX
    x%x = this%a * 2
    x%y = this%b * 2
    x%z = this%c * 2
  END PROCEDURE a_toX
END SUBMODULE Procedures_for_X
...

在 Fortran 2008 之前,您有时可以使用模拟上述方法的替代方法 - 过程的实现在使用该模块的单独编译的一组外部过程中进行。需要注意的是,外部过程不能看到它们自己的界面。

MODULE ConversionStuff
  IMPLICIT NONE
  TYPE :: A_T
    REAL :: a, b, c
  CONTAINS
    PROCEDURE :: toX => a_toX
  END TYPE A_T
  TYPE :: X_T
    REAL :: x, y, z
  CONTAINS
    PROCEDURE :: toA => x_toA
  END TYPE x, y, z
  INTERFACE
    FUNCTION a_toX(this) RESULT(x)
      IMPORT :: A_T
      IMPORT :: X_T
      IMPLICIT NONE
      CLASS(A_T), INTENT(IN) :: this
      TYPE(X_T) :: x
    END FUNCTION a_toX
    FUNCTION x_toA(this) RESULT(a)
      IMPORT :: A_T
      IMPORT :: X_T
      IMPLICIT NONE
      CLASS(X_T), INTENT(IN) :: this
      TYPE(A_T) :: a
    END FUNCTION x_toA
  END INTERFACE
  PRIVATE :: a_toX
  PRIVATE :: x_toA
END MODULE ConversionStuff

FUNCTION A_toX(this) RESULT(x)
  USE ConversionStuff
  IMPLICIT NONE
  CLASS(A_T), INTENT(IN) :: this
  TYPE(X_T) :: x
  ...etc...
END FUNCTION A_toX

对于第二种方法,使用 Fortran 的可访问性属性(PUBLIC 和 PRIVATE)存在一些限制。

请注意,问题与命名空间无关,因为通常定义了这个概念。

【讨论】:

  • 我很感激。当我可以访问它们时,我会给第二个建议和子模块一个镜头。抱歉回复慢。
  • 我可以看到这在某些过程很长的情况下很有帮助,但是对于一堆小的、相当简单的转换函数来说,这似乎接口所需的额外代码比只保留所有内容更糟糕在一个文件中。我错过了什么吗?
  • 真的没有“额外的代码”——你只是将接口与实现分开。您可以根据需要将函数拆分到任意数量的文件中。请参阅software.intel.com/en-us/blogs/2015/07/07/… 了解更多信息。
【解决方案2】:

在处理其他事情并在将近 2 个月后回到这个问题。我发现一些我认为对于这种特定用途来说更加简单和优雅的东西。我将保留以前接受的答案,因为它肯定回答了问题,但这是另一种方法。

它使用 include 关键字。直到现在我才明白它在编译包含文件之前不会编译包含文件。也许有一些我不明白的地方,但是对于这种我只想拆分为多个文件以使我的单个文件不是很大的情况,我认为这种方法值得我付出代价,因为它不是一个模块。如果有什么我想念的,请告诉我。

我的解决方案如下。

Module ConversionStuff
  implicit none

  type A_T
    real :: a, b, c
  contains
    procedure :: toX => a_toX
  end type A_T

  type X_T
    real :: x, y, z
  contains
    procedure :: toA => x_toA
  end type X_T

  contains

  include "A.f90"
  include "X.f90"

End Module ConversionStuff

A.f90

function a_toX(this) result(x)

    class(A_T), intent(inout) :: this
    type(X_T) :: x

    x%x = this%a * 2
    x%y = this%b * 2
    x%z = this%c * 2

end function a_toX

X.f90

function x_toA(this) result(a)

    class(X_T), intent(inout) :: this
    type(A_T) :: a

    a%a = this%x * 0.5
    a%b = this%y * 0.5
    a%c = this%z * 0.5

 end function x_toA

【讨论】:

  • 嗯,这个已经在本站讨论过很多次了,但是对于它是否真的“更加简洁优雅”的看法却大相径庭。
猜你喜欢
  • 1970-01-01
  • 2017-01-02
  • 2015-03-08
  • 2015-01-11
  • 1970-01-01
  • 1970-01-01
  • 2014-02-11
  • 2011-12-09
  • 1970-01-01
相关资源
最近更新 更多