4

私は Java でプログラミングをして数年になります。ただし、現在、Fortran をサンプル コード (77 標準) として使用するコースを受講しています。私は常に Fortran を古い言語と見なしてきましたが、gfortran コンパイラーを使用して 2003 標準の最新の実装を試し、そのメリットを自分の目で確かめることにしました。これまでのところ、最新の機能には驚かされましたが、以下の例で示されている 1 つの問題に遭遇しました。

    module mod1
      type type1
        real :: x
        real :: y
        contains
        procedure :: compute
      end type type1
      contains
      subroutine compute(this)
        class(type1) :: this
        this%y = this%x*2 - 1
        write (*,*) this%x,this%y
      end subroutine
    end module mod1

    module mod2
      type type2
        real :: x
        real :: y
        contains
        procedure :: compute
      end type type2 
      contains
      subroutine compute(this)
        class(type2) :: this
        this%y = this%x - 5
        write (*,*) this%x,this%y
      end subroutine
    end module mod2

    program test
      use mod1
      use mod2
      implicit none
      type(type1) myType1
      type(type2) myType2
      myType1%x = 4
      myType2%x = 5
      call myType1%compute
      call myType2%compute
    end program test

これにより、コンパイル エラーが生成されます: 「(1) の引数 'this' の型が一致しません。TYPE(type2) を CLASS(type1) に渡しました」というcall myType2%computeステートメントへの参照。

私の問題は範囲の問題です。ステートメントを通じて、class(<class_name>) :: thisコンパイラはサブルーチンを特定の派生型またはその子孫にバインドできるはずです。ここから、コンパイラがサブルーチン内でローカルに開始して の特定のインスタンスの祖先ツリーを上に進む変数定義を検索することは概念的に難しくないようですthisthis%これにより、いくつかのステートメントの後で、型にバインドされたプロシージャが読みにくくなる傾向がある明示的なステートメントがすべて削除されます。例えば、

    this%tempNew(xI) = this%lamda*this%temp(xI-1)+(1-2*this%lamda)*this%temp(xI)+this%lamda*this%temp(xI+1)

よりも読み取り/書き込み可能性がはるかに低いようです

    tempNew(xI) = lamda*temp(xI-1)+(1-2*lamda)*temp(xI)+lamda*temp(xI+1)

後者の場合、class(<class_name>) :: this各変数をどこにバインドする必要があるかは、ステートメントから明らかです。

もう 1 つの結果は、2 つの別個の派生型が同じ名前のバインドされたサブルーチンを持つことができないように見えることです (エラー メッセージが示すように)。これを回避する 2 つの一般的な方法を見てきました。compute_type1まず、各サブルーチンをandのように明示的に呼び出しますcompute_type2。これらのサブルーチンにアクセスすると、コードが非常に見苦しく冗長に見えます。たとえばcall myType1%compute_type1。2 番目のオプション (たとえばOverloaded fortran interface with different ranksType-bound function overloading in Fortran 2003を参照) の方が適切と思われるのは、バインド名とプロシージャ名を区別することです。たとえば、型定義には以下が含まれます。procedure :: compute type => compute_type1. これにより、サブルーチンにアクセスする際の問題は解決しますが、同じバインディング名を実装する多くの派生型を持つ大規模なプロジェクトを開発する際に問題が発生することがあります。特定のプロジェクトで使用したサブルーチン名と使用していないサブルーチン名を追跡する必要はありません。これにより、名前が非常に長くなり、最終的に読みにくくなる傾向があります。

だから私の質問には3つの要素があります:

  • this%<var_name>型バインド プロシージャのクラス メンバーの明示的な型付けに代わる、よりクリーンな方法はありますか?
  • class(<class_name>) :: thisステートメントに基づいてプロシージャをバインドする必要があることをコンパイラに認識させる方法はありますか? サブルーチン/関数名をオーバーロードする現在の方法は、これらを型にバインドすることを許可していない 90/95 標準のアーティファクトのようです。
  • そうでない場合、この実装に関連するパフォーマンスの向上はありますか? これらの問題は両方とも、コンパイル時に対処できるように思われますが、表現力を向上させるために喜んで犠牲にします。
4

1 に答える 1

5

これはより拡張されたコメントですが、コンパイラが失敗したために推測を余儀なくされているようです。エラーなしで gfortran 4.8.3 を使用してコードをコンパイルしましたが、期待どおりの結果が得られました。また、あなたが望んでいることは起こるべきだと私には思えます。

もう 1 つの結果は、2 つの別個の派生型が同じ名前のバインドされたサブルーチンを持つことができないように見えることです (エラー メッセージが示すように)。

両方のサブルーチンが呼び出されている間、computeそれらは別々のモジュールにあり、これは許可されていますが、useステートメントはcall compute(...)(あなたが行っていない) あいまいになります。型定義が同じモジュールにある場合は、このprocedure :: compute => compute_typexトリックに頼る必要がありますが、call mytype1%computeそれでも問題ありません。

compute型バインディングを介してサブルーチンを公開している場合は、それらをprivateモジュールのようにするか、少なくとも明示的にしないことをお勧めしuseます。【つまり、持つuse mod1, only : type1

あなたがサブルーチンで立ち往生しているかどうかについてはtype%...、はい、そう思います。とはいえ、Fortran 2008 の下では、次のassociate構造があります。

subroutine compute(this)
  class(type1), intent(inout) :: this
  associate (x => this%x, y => this%y)
    ...
  end associate
end subroutine

しかし、この場合、それはあまり得になりません。そして、私が詳述しない他の恐ろしいトリックがあります.

于 2014-01-24T23:35:43.050 に答える