5

Fortran では、いくつかのサブルーチンの 1 つを指すことができる派生型内にプロシージャ ポインターが必要です。この問題は SO ではよくあるようです:

構造型のプロパティとしての Fortran 保存プロシージャ

Fortran 2003 での型バインド プロシージャのオーバーロード

このタイプ バインドされたジェネリック サブルーチン呼び出しに一致する特定のサブルーチンがありません

プロシージャの引数を持つジェネリック型バインド プロシージャ

バインドされたプロシージャを引数として入力

いくつか挙げると。関数に関するこの質問に対する答えは、最初の参考文献で非常にうまく提供されています。

ただし、型バインド プロシージャ ポインターがサブルーチンを指している場合に、このようなコードを適切に開発する方法については、まだ明確ではありません。問題は、返されるものに関連付けられた型がないように思われる (実際には何も返されないため)。

また、より最近の fortran の標準 (2003、2008) には単純な解決策が存在する可能性がありますが、この解決策はすべてのコンパイラで機能しない可能性があり、将来問題になる可能性があるというニュアンスを指摘したいと思います。そのため、コンパイラに適したソリューションに興味があります。

現在動作する小さなコード (以下を参照) がありますが、大きなコードでは、派生型でプロシージャ ポインターを使用するファイルで内部コンパイラ エラー (以下も参照) が発生します。私の質問は次のとおりです。以下のコードに何ができますか

1) 明示的なインターフェースを厳密に使用する

2) コンパイラに渡される情報を最大化する

3) コードができるだけ多くのコンパイラ間で移植可能であることを確認します (つまり、fortran 90 / 95 標準を使用します)。

上記をどの程度満たすことができますか(1が最も重要です)?上記の基準をすべて満たすことは可能ですか?「これらの基準をすべて満たす」というのは主観的なものであることは承知していますが、サブルーチンではなく関数に関する同じ質問に対する答えは「はい」であると主張します。

 gcc version 5.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project)

小さなコード:

  module subs_mod
  implicit none
  public :: add,mult
  contains
  subroutine add(x,y,z)
    implicit none
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    x = y+z
  end subroutine
  subroutine mult(x,y,z)
    implicit none
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    x = y*z
  end subroutine
  end module

  module type_A_mod
  use subs_mod
  implicit none
  public :: type_A,init,operate
  type type_A
    procedure(),pointer,nopass :: op
  end type
  contains
  subroutine init(A,op)
    implicit none
    external :: op
    type(type_A),intent(inout) :: A
    A%op => op
  end subroutine
  subroutine operate(A,x,y,z)
    implicit none
    type(type_A),intent(in) :: A
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    call A%op(x,y,z)
  end subroutine
  end module

  program test
  use type_A_mod
  use subs_mod
  implicit none
  type(type_A) :: A
  integer :: x
  call init(A,mult)
  call operate(A,x,3,5)
  write(*,*) 'x = ',x
  end program

大きなコードでのコンパイラ エラー:

    f951.exe: internal compiler error: Segmentation fault
    libbacktrace could not find executable to open
    Please submit a full bug report,
    with preprocessed source if appropriate.
    See <http://sourceforge.net/projects/mingw-w64> for instructions.

アップデート

これは、コンパイラにより多くの情報を提供する小さな変更ですが、大きなコードではこれを試していません。ただし、恣意的なようで、役立つかどうかはわかりません。

  ...
  function add(x,y,z) result(TF)
  ...
    logical :: TF
    x = y+z
    TF = .true.
  end function
  function mult(x,y,z) result(TF)
  ...
    logical :: TF
    x = y*z
    TF = .true.
  end function
  end module

  module type_A_mod
  ...
  type type_A
    procedure(logical),pointer,nopass :: op
  end type
  ...
  subroutine init(A,op)
    implicit none
    logical,external :: op
  ...
  end subroutine
  subroutine operate(A,x,y,z)
  ...
    logical :: TF
    TF = A%op(x,y,z)
  end subroutine
  end module

  program test
  ...
  end program

解決策のコメント (@IanH によって提供された) 解決策についてコメントするだけです: もう 1 つのしわがありました。それは、Fortran 2003 の新機能によると、ステートメントを含める必要がある抽象インターフェイスにいくつかの派生型が入力されていことですImport。派生型の入力を抽象インターフェイスに認識させるため。これは、大きなコードに適用される小さな実用的な例であり、私が抱えていた内部コンパイラエラーを軽減します:)

  module DT_mod
  implicit none
  private
  public :: DT
  type DT
    integer :: i
  end type
  contains
  end module

  module subs_mod
  use DT_mod
  implicit none
  private
  public :: add,mult,op_int

  abstract interface
  subroutine op_int(d,x,y,z)
    import :: DT
    implicit none
    type(DT),intent(inout) :: d
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
  end subroutine
  end interface

  contains
  subroutine add(d,x,y,z)
    implicit none
    type(DT),intent(inout) :: d
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    x = y+z
    d%i = 1
  end subroutine
  subroutine mult(d,x,y,z)
    implicit none
    type(DT),intent(inout) :: d
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    x = y*z
    d%i = 2
  end subroutine
  end module

  module type_A_mod
  use DT_mod
  use subs_mod
  implicit none
  private
  public :: type_A,init,operate
  type type_A
    procedure(op_int),pointer,nopass :: op
  end type
  contains
  subroutine init(A,op)
    implicit none
    procedure(op_int) :: op
    type(type_A),intent(inout) :: A
    A%op => op
  end subroutine
  subroutine operate(A,d,x,y,z)
    implicit none
    type(DT),intent(inout) :: d
    type(type_A),intent(in) :: A
    integer,intent(inout) :: x
    integer,intent(in) :: y,z
    call A%op(d,x,y,z)
  end subroutine
  end module

  program test
  use type_A_mod
  use subs_mod
  use DT_mod
  implicit none
  type(type_A) :: A
  type(DT) :: d
  integer :: x,y,z
  y = 3; z = 5
  call init(A,mult)
  call operate(A,d,x,y,z)
  write(*,*) 'x,y,x = ',y,z,x
  write(*,*) 'd%i = ',d%i
  end program

どんな助けでも大歓迎です。

4

2 に答える 2