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
どんな助けでも大歓迎です。