新しいプロジェクトで、Fortran2003 のオブジェクト指向機能を使用することを検討しています。私が試したことの 1 つは、多相型へのポインターを返す関数 (サブルーチンではない) を指すプロシージャー ポインターです。さまざまなコンパイラからさまざまな結果が得られるため、そのような構成が合法であるかどうか疑問に思います (以下を参照)。
具体的な例として、次の関数インターフェイスを考えてみましょう。
abstract interface
function if_new_test(lbls) result(t)
import :: test_t
class(test_t),pointer :: t
character(len=*),intent(in) :: lbls(:)
end function if_new_test
end interface
また、使用するコードには、このインターフェイスを使用して関数を指すことができるプロシージャ ポインターが必要です。
procedure(if_new_test),pointer :: nt
gfortran (4.7.2) がこのプロシージャ ポインタ宣言について次のメッセージで不平を言うため、これが合法かどうかを尋ねています。
エラー: (1) の CLASS 変数 'nt' は、ダミー、割り当て可能、またはポインターでなければなりません
このエラーメッセージ自体がポインターであるため、私は理解できませんnt
。また、それが指す関数が返すものもポインターです。
参考までに、この例の完全なソース コードを次に示します。まず、私の派生型、インターフェイス、および関数/サブルーチンを含むモジュール:
module test_m
implicit none
type :: test_t
character(len=10) :: label
contains
procedure :: print => print_test
end type test_t
type,extends(test_t) :: test2_t
character(len=10) :: label2
contains
procedure :: print => print_test2
end type test2_t
abstract interface
function if_new_test(lbls) result(t)
import :: test_t
class(test_t),pointer :: t
character(len=*),intent(in) :: lbls(:)
end function if_new_test
subroutine if_make_test(t,lbls)
import :: test_t
class(test_t),pointer :: t
character(len=*),intent(in) :: lbls(:)
end subroutine if_make_test
end interface
contains
subroutine print_test(self)
implicit none
class(test_t),intent(in) :: self
print *, self%label
end subroutine print_test
subroutine print_test2(self)
implicit none
class(test2_t),intent(in) :: self
print *, self%label, self%label2
end subroutine print_test2
function new_test(lbls) result(t)
implicit none
class(test_t),pointer :: t
character(len=*),intent(in) :: lbls(:)
call make_test(t,lbls)
end function new_test
function new_test2(lbls) result(t)
implicit none
class(test_t),pointer :: t
character(len=*),intent(in) :: lbls(:)
call make_test2(t,lbls)
end function new_test2
subroutine make_test(t,lbls)
implicit none
class(test_t),pointer :: t
character(len=*),intent(in) :: lbls(:)
allocate(test_t::t)
t%label = lbls(1)
end subroutine make_test
subroutine make_test2(t,lbls)
implicit none
class(test_t),pointer :: t
character(len=*),intent(in) :: lbls(:)
allocate(test2_t::t)
select type(t) ! so the compiler knows the actual type
type is(test2_t)
t%label = lbls(1)
t%label2 = lbls(2)
class default
stop 1
end select
end subroutine make_test2
end module test_m
そして、このモジュールを使用するメインプログラム:
program test
use test_m
implicit none
class(test_t),pointer :: p
procedure(if_make_test),pointer :: mt
procedure(if_new_test),pointer :: nt
mt => make_test
call mt(p,["foo"])
call p%print
deallocate(p)
mt => make_test2
call mt(p,["bar","baz"])
call p%print
deallocate(p)
p => new_test(["foo"])
call p%print
deallocate(p)
p => new_test2(["bar","baz"])
call p%print
deallocate(p)
nt => new_test
p => nt(["foo"])
call p%print
deallocate(p)
nt => new_test2
p => nt(["bar","baz"])
call p%print
deallocate(p)
end program test
プログラムは最初にサブルーチン make_test
とを介してオブジェクトを作成しますmake_test2
。私のテストでは、これは私が試したすべてのコンパイラで動作します。次に、関数 new_test
andを直接呼び出してオブジェクトを作成しnew_test2
ます。これは私のテストでも機能します。最後に、これらの関数を介してオブジェクトを再度作成する必要がありますが、手続きポインタを介して間接的に作成する必要がありますnt
。
上記のように、gfortran (4.7.2) は の宣言をコンパイルしませんnt
。
ifort (12.0.4.191) は、行で内部コンパイラ エラーを生成しますnt => new_test
。
pgfortran (12.9) は警告なしでコンパイルされ、実行可能ファイルは期待される結果を生成します。
Fortran2003 によると、私がやろうとしていることは違法ですか、それともそのような機能に対するコンパイラのサポートはまだ不十分ですか? 関数の代わりにサブルーチンを使用する必要がありますか (動作しているようです)。