1

インターフェイスを使用して、さまざまなタイプのさまざまなサブルーチンを呼び出そうとしていますが、ポインター属性を使用すると機能しないようです。たとえば、このサンプルコードを見てください

 MODULE ptr_types
     TYPE, abstract :: parent
        INTEGER :: q
     END TYPE
     TYPE, extends(parent) :: child
        INTEGER :: m
     END TYPE
     INTERFACE ptr_interface
        MODULE PROCEDURE do_something
     END INTERFACE
     CONTAINS
        SUBROUTINE do_something(atype)
           CLASS(parent), POINTER :: atype
           ! code determines that this allocation is correct from input
           ALLOCATE(child::atype)
           WRITE (*,*) atype%q
        END SUBROUTINE
  END MODULE
  PROGRAM testpass
     USE ptr_types
     CLASS(child), POINTER :: ctype

     CALL ptr_interface(ctype)
  END PROGRAM

これによりエラーが発生します Error: There is no specific subroutine for the generic 'ptr_interface' at (1)

ただし、サブルーチンでポインター属性を削除すると、正常にコンパイルされます。さて、通常これは問題にはなりませんが、私のユースケースでは、主に必要に応じて割り当てることができるように、その引数をポインターとして扱うことができる必要があります。

助言がありますか?私はfortranに慣れていないので、何かを見落としているかもしれません

編集:親サブルーチンに割り当てを入れるのを忘れました。最初の入力は割り当てられていません

EDIT 2これは、発信者側のキャストを使用した2回目の試みです

    MODULE ptr_types
       TYPE, abstract :: parent
        INTEGER :: q
        END TYPE
        TYPE, extends(parent) :: child
          INTEGER :: m
        END TYPE
        TYPE, extends(parent) :: second
           INTEGER :: meow
        END TYPE
        CONTAINS
           SUBROUTINE do_something(this, type_num)
              CLASS(parent), POINTER :: this
              INTEGER type_num
              IF (type_num == 0) THEN
                 ALLOCATE (child::this)
              ELSE IF (type_num == 1) THEN
                 ALLOCATE (second::this)
              ENDIF
           END SUBROUTINE
     END MODULE
     PROGRAM testpass
        USE ptr_types
        CLASS(child), POINTER :: ctype
        SELECT TYPE(ctype)
        CLASS is (parent)
           CALL do_something(ctype, 0)
        END SELECT
        WRITE (*,*) ctype%q
     END PROGRAM

ただし、これはまだ失敗します。selectステートメントでは、親が子を拡張する必要があると不平を言っています。これは、型の安全性のためにポインター属性を扱うときの制限によるものだと確信していますが、ジェネリック割り当てのためにポインターをその親型に変換する方法を探しています。型ごとに個別の割り当て関数を作成し、それらがインターフェイスなどで衝突しないようにする必要はありません。

うまくいけば、この例は、私が達成しようとしていることをもう少し明確に示しています。より良い方法を知っているなら、私に知らせてください

4

3 に答える 3

2

ハイ パフォーマンス マークで示されているように、 への呼び出しの実引数と仮引数の宣言された型に不一致がありますptr_interface。これは、仮引数にポインターまたは割り当て可能な属性がある場合は許可されません。F2008 の 12.5.2.5p2 を参照してください。

この制限には単純な理由があります (これは F2008 標準の Note 12.27 で説明されています)。これがないと、サブルーチンが仮引数を実引数と互換性のない型に割り当てる可能性があります。たとえばParent、プログラムのどこかに の別の拡張があった場合を想像してみてください -Child型階層内の の兄弟です。do_somethingプロシージャが仮引数をその兄弟の型に割り当てた場合、呼び出しスコープに戻って、Child実際には他の互換性のない (Child の拡張ではない) 型である型として宣言されたものがあります。

do_something プロシージャーがその Thing を Child 型以外に割り当てることができない場合は、その仮引数を Child 型にします。Parent の拡張である他の型に割り当てることができる場合は、実引数型の宣言型も Parent にする必要があります。SELECT TYPE コンストラクトを使用して、呼び出しスコープ内の Child 型のオブジェクトにダウンキャストできます。

あなたの編集に続いて、私の提案はあなたのメインプログラムが次のようになることでした:

PROGRAM testpass
  USE ptr_types
  IMPLICIT NONE           ! <-- 
  CLASS(Parent), POINTER :: ctype
  !***
  ! ctype here is a pointer with undefined association status, 
  ! (so no concept of dynamic type) and declared type Parent.
  CALL do_something(ctype, 0)
  ! Assuming successful ALLOCATE(Child :: xxx) in the procedure, 
  ! ctype here is an associated pointer with dynamic type Child.
  SELECT TYPE(ctype)
  CLASS is (Child)
    ! Declared type of ctype in here is Child.  Dynamic type 
    ! in this specific case is also Child, but this block would 
    ! also be executed if the dynamic type was a further extension
    ! of Child, because a CLASS IS guard was used.  (A TYPE IS 
    ! guard requires an exact match of dynamic type.)
    ! 
    ! If the allocate in do_something allocated the dummy argument 
    ! to be of type second or nullified the argument, then this 
    ! block of code would not be executed.  If do_something left 
    ! the association status of the pointer undefined, then 
    ! your program is non-conforming, and anything could happen.
    WRITE (*,*) ctype%m   
    ! Continue to work with ctype as a thing with declared type 
    ! Child inside this block of the select type construct.
  END SELECT
  ! ctype back to having a declared type of Parent.
  WRITE (*,*) ctype%q
  ! Don't forget deallocation!
 END PROGRAM
于 2013-06-26T13:38:29.490 に答える
0

あなたのラインを変えたら

 CLASS(child), POINTER :: ctype

 CLASS(parent), POINTER :: ctype

次に、プログラムがコンパイルおよび実行されます。私自身、このオブジェクト指向 Fortran のすべてにまったく慣れていないので、この場合のランクとタイプと種類のマッチングのルールを示し、間違いを明確にする標準の条項を指摘するのに苦労しています。あなたの間違いは、言語の最新機能を実装していないコンパイラを使用することかもしれません。一方、私のコンパイラ (インテル Fortran 13.1) は、最新の機能をあなたのコンパイラと同じように正しく実装していない可能性があります。

(過去のフォームでは、SO の IanH という名前の人が後で通りかかって明確になります。)

ただし、私が学んだことの 1 つは、コンパイラが Fortran 2003 に (十分に) 準拠している場合、多くの操作を簡単にするのALLOCATABLEではなく変数を作成POINTERし、不要なメモリを解放する責任をコンパイラに渡すことです。Fortran での動的メモリ管理のためのポインターはもう必要ありません。

于 2013-06-26T09:29:30.577 に答える
0

あなたの問題は、サブルーチン do_something の引数の POINTER 属性にあると思います。それを削除すると、すべてが機能するはずです。

于 2013-06-26T12:11:21.963 に答える