2016-05-25 23 views
1

派生型Vを作成しました。追加関数 を使用して、演算子+を使用できます。Fortran:関数の戻り値の型からの値へのアクセス

は、しかし、私は操作が実行されていない

z = u + v 

を行うとき。 z%kn にアクセスしていないためだと思います。

私は

Call vsum(z, u, v) 

を行う場合は、以下の

期待通りしかしすべての作品は、派生型と のオーバーロード関数VADDの宣言です。

Module vtest 

Type :: V 

    Character (Len=8) :: kn 
    Real, Allocatable :: vc(:) 

    Contains 

    Procedure :: vadd 
    Generic :: Operator (+) => vadd 

End Type vtest 

Contains 

Function vadd (b, c) Result (a) 
    Type (V) :: a 
    Class (V), Intent (In) :: b, c 

    !!$ In vsum, use is made of a% kn 
    Call vsum (a, b, c) 

End Function vadd 

Subroutine vsum (ta, tb, tc) 
    Type (V), Intent (InOut) :: ta 
    Type (V), Intent (In) :: tb, tc 

    Logical :: la, lb, lc 

    la = .False.; lb = .False.; lc = .False. 

    Select Case (ta%kn) 

    Case ("Real32") 
    If (Allocated (ta%vc)) la = .True. 
    If (Allocated (tb%vc)) lb = .True. 
    If (Allocated (tc%vc)) lc = .True. 
    If (la .And. lb .And. lc) Then 
     ta%vc = tb%vc + tc%vc 
    End If 

    End Select 

End Subroutine vsum 

End Module vtest 


Program test 
Use vtest 
Type (V) :: z 

    z% kn = "Real32" 
    Allocate (z% vc_real32(3)) 
    Write (*,*) "z = u + v" 
    Write (*,*) "z% kn: ", z% kn 
    z = u + v 
    Write (*,*) "z% kn: ", z% kn 
    Write (*,*) "z: ", z% vc_real32 

End Program vtest 
+1

'vsum'のコードを表示してください。 –

+0

コードはまだ不完全です。ほとんどの場合mcve http://stackoverflow.com/help/mcveオペレータの呼び出しとその周囲がありません。表示されていない詳細にバグがある可能性があります。完全にコンパイル可能なコードを用意する必要があります。コードの出力を含めます。操作が実行されていないことをどのように診断しましたか?代わりに何が起こったのですか? –

答えて

2

サブルーチンvsumを見てみましょう。そのサブルーチンで行われる作業は、3つのオブジェクトta,tbおよびtcのすべてのコンポーネントの定義に依存します。期待通りに合計を処理するには、割り当て可能なすべてのコンポーネントを割り当てる必要があり、一致する場合はta%kn'Real32'にします。

には完全な作業例もありませんが、あなたが言うように'Real32'に設定されている

call vsum(z, u, w) ! V is the name of the type, so call the variable w 

z%knのような呼び出しがある場合に、物事が動作します。

しかし、定義された操作

z = u + w 

call vsum (a, b, c) ! Actual arguments "z", u, w. 

今すぐに存在している関数の参照

z = vadd(u, w) 

があり、aでの関数の結果でありますvadd。その結果、intent(out)aという仮引数のように、最初は未定義です。 vaddzを通過するとき、本質的に、意味

は未定義成分knと未割り当てコンポーネントvcvsumにそれを行います。したがって、合計の要件は満たされません(実際にはselect caseが無効な参照を形成します)。


この問題を解決する方法についてもお答えしたいと思います。

vsumでは、実質的に「結果」からの操作の種類を取り入れています。その代わり、

Subroutine vsum (ta, tb, tc) 
    Type (V), Intent (Out) :: ta 
    Type (V), Intent (In) :: tb, tc 

    Logical :: lb, lc 

    lb = .False.; lc = .False. 

    ! In here we probably want some consistency checking... 
    Select Case (tb%kn)  
    Case ("Real32") 
    If (Allocated (tb%vc)) lb = .True. 
    If (Allocated (tc%vc)) lc = .True. 
    If (lb .And. lc) Then 
     ta%vc = tb%vc + tc%vc ! ta%vc being automatically allocated 
    End If 
    End Select 

End Subroutine vsum 

このようなものは、当然、その結果から、操作の種類を取るために(タイトルから)あなたの見せかけの欲求に対応していません。とすることができますが、元のサブルーチンのアプローチでは、ただし、Fortranの機能の哲学ではない場合を除きます。

定義済みの操作を使用する場合は、割り当ての左側で操作を定義することはできません。式u+wでは、左辺は存在しませんが、定義された操作は依然として動作すると予想されます。それは声明

z = u + w 

あなたは「zuwに適用される操作+の結果である」と言っていないで、と言うこともあります。しかし、:uwに適用された操作+が評価され、結果は(定義済みまたは暗黙の割り当てによって)z "に割り当てられます。 「結果のタイプ」に達する前にその割り当てがあります。これが私が以前に引用した実際の引数としてzを入れた理由です。

+0

+1特に最後の段落の場合。 Fortran関数は、割り当ての左辺にあるものを決して「見る」ことはありません。彼らは義務に全く置かれる必要はありません!彼らはいくつかの式を計算し、その式は何らかの形で呼び出しコードによって使用されます。 –

+0

つまり、vadd zを渡すと、定義されていないコンポーネントknと割り当てられていないコンポーネントvcを持つvsumになります。したがって、合計の要件は満たされません(実際、選択されたケースは無効な参照を形成します)。 ---これはまさに起きていることです。 – Zeus

+0

修正を試みましたが、結果が正しく返されません。関数 'vadd'で 'vsum'を呼び出した後に配列の値を出力して、正しい値を取得しました。しかし、メインプログラムでは、結果は未定義です。 – Zeus