2016-04-12 15 views
5

Fortranでは、いくつかのサブルーチンの1つを指すことができる派生型内にプロシージャポインタが必要です。少数を示すためにFortranプロシージャの派生型のサブルーチンへのポインタ

Fortran save procedure as property in derived type

Type bound procedure overloading in Fortran 2003

There is no matching specific subroutine for this type bound generic subroutine call

Generic type-bound procedures with procedure arguments

Type bound procedure as arguments

:この問題は、SOに共通のようです。 関数のこの質問に対する回答は、最初の参照で非常にうまく提供されています。

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

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

私は大きなコードで、派生型のプロシージャポインタを使用するファイルに内部コンパイラエラー(以下も示す)が表示されています。私の質問は:私は厳密にコンパイラ

3)コードはできるだけ多くのコンパイラ間の移植性があることを確認しに渡された情報を最大化)明示的なインターフェイス

2を使用)

1に以下のコードに何ができます(つまり、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. 

UPDATE

ここでは、コンパイラより多くの情報を与える小さな変更は、だけど私は大きなコードでこれを試していない。しかし、それは恣意的と思われ、助けになるかどうかは分かりません。、一つの追加のシワがあった、それは私はいくつかの派生型がThe New Features of Fortran 2003に応じて抽象インタフェースを、入っていたということでした。

... 
    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 

SOLUTIONは ちょうど(@IanH提供)ソリューションにコメントするコメント抽象的なインターフェイスに入力派生型が認識されるようにするには、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 

を持っていたすべてのヘルプは大歓迎です。

+0

違いを表示するだけで、更新2で変更された内容を確認するのは難しいです。特に、コード内に空白行を使用しない(読みにくい)ことを考慮すると、 –

+0

ところで、gfortranで '-std = f95'を実行すると、実際にFortran 2003以降のものがいくつあるのかがわかります。 –

+0

ありがとう@VladimirF、私は最近これを試しました、それは有用でした。 – Charlie

答えて

5

プロシージャポインタはFortran 2003までは標準言語の一部ではなかったので、それらをまったく使用したい場合は、Fortran 95との互換性はありません。

内部コンパイラエラーは、コンパイラに提供されたソースに関係なく、コンパイラのエラーです。

タイプバインドされたプロシージャポインタのようなものはありません。型拘束型プロシージャーは、派生型構造体のCONTAINSの後に宣言されるものか、プロシージャー・ポインターを持ちます。これは、タイプのコンポーネントまたはスタンドアロン・オブジェクトです。コンポーネントであるプロシージャポインタは、派生型のオブジェクトの値の一部です。実行時に異なるプロシージャに関連付けることができます。型バインドされたプロシージャは、型宣言の固定プロパティです。

プロシージャ・ポインタ(またはダミー・プロシージャ)に明示的なインタフェースを設定する場合は、プロシージャ宣言文のかっこ内にインタフェース名を指定する必要があります。

procedure(interface_name_goes_here) [, pointer, ...] :: thing_being_declared 

設けられたインターフェース名が(以前に異なるプロシージャ宣言ステートメントによって宣言を含む)アクセス可能な具体的な手順、または抽象インタフェースの名前の名前とすることができます。

(プロシージャ宣言文のインタフェース名がタイプである場合、サンプルコードのコンポーネントの場合と同様に、宣言されたプロシージャは、暗黙のインタフェースを持つ、指定された型の結果を持つ関数です。

プロシージャ宣言文のインタフェース名が完全に欠けている場合、宣言されたプロシージャは、暗黙のインタフェースを持つ関数またはサブルーチン(後でその使用が一致する必要があります)である可能性があります)

したがって、明示的なインターフェイスを持つプロシージャポインタコンポーネントを、同じ特性を持つ関数(質問タイトルとは反対)に宣言したいと仮定した場合、コードのあなたの第二ストレッチでaddまたはmultなどの:

TYPE type_A 
    PROCEDURE(the_interface), POINTER, NOPASS :: op 
END TYPE type_A 

ABSTRACT INTERFACE 
    FUNCTION the_interface(x, y, z) RESULT(tf) 
    IMPLICIT NONE 
    ! function modifying arguments - poor style!!! 
    INTEGER, INTENT(INOUT) :: x 
    INTEGER, INTENT(IN) :: y, z 
    LOGICAL :: tf 
    END FUNCTION the_interface 
END INTERFACE 

あなたが手続きポインタが(その引数を変更する機能に好適である)明示的なインタフェースを持つサブルーチンになりたい場合は - 抽象インタフェースを変更適切に。

initサブルーチン内の仮手続は、ポインタである必要はありません - initの内側にあなたは何op事の参照を変更していない - あなたは、単にそれを別のポインタを指している:

PROCEDURE(the_interface) :: op 

すると、あなたのダミープロシージャとプロシージャのポインタは明示的なインタフェースで宣言されているので、合理的なコンパイラが特性の不一致を診断すると期待します。

+0

これは非常に有望です。私はこの実装に残っている1つの問題があります。大きなコード(小さなコードでinit(A、mult)を呼び出す)でプロシージャを初期化しようとすると、 "(1)でダミープロシージャの演算子 'のインターフェイスの不一致が発生しています:INTENT mismatch in引数 'x' "。つまり、以前は内部コンパイラエラーが発生したファイルをコンパイルすることができました。 – Charlie

+0

これは完全に機能しました。ありがとうございました。 – Charlie

関連する問題