对于一个新项目,我正在考虑使用Fortran2003的面向对象特性。我尝试过的一件事是一个过程指针,它指向一个函数(而不是子例程),它返回一个指向多态类型的指针。我不知道这样的构造是否合法,因为我从不同的编译器获得了不同的结果(参见下面)。
作为一个具体示例,请考虑以下函数接口:
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)抱怨这个过程指针声明带有消息:
错误:类变量'nt‘在(1)处必须是虚拟的、可分配的或指针
我不理解这个错误消息,因为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和new_test2来创建对象,这也适用于我的测试。最后,应该再次通过这些函数创建对象,但通过过程指针nt间接地创建对象。
如上所述,gfortran (4.7.2)不编译nt的声明。
ifort (12.0.4.191)在行nt => new_test上产生内部编译器错误。
pgfortran (12.9)在没有警告的情况下编译,可执行文件产生预期的结果。
那么,根据Fortran2003,我试图做的是非法的,还是编译器对这些特性的支持仍然不够?我应该只使用子程序而不是函数(因为这似乎有效)?
发布于 2013-02-15 16:56:54
你的代码似乎没问题。我可以用Intel 13.0.1和NAG5.3.1编译它,没有任何问题。较老的编译器在Fortran 2003更“花哨”的特性方面可能有问题。
根据问题的不同,您也可以使用可分配的类型而不是指针。应该更好地防止内存泄漏,另一方面,由于一个函数,您将无法返回多态类型:
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), allocatable :: t
character(len=*),intent(in) :: lbls(:)
end function if_new_test
subroutine if_make_test(t,lbls)
import :: test_t
class(test_t), allocatable :: t
character(len=*),intent(in) :: lbls(:)
end subroutine if_make_test
end interface
contains
subroutine print_test(self)
class(test_t), intent(in) :: self
print *, self%label
end subroutine print_test
subroutine print_test2(self)
class(test2_t), intent(in) :: self
print *, self%label, self%label2
end subroutine print_test2
subroutine make_test(t,lbls)
class(test_t), allocatable :: t
character(len=*),intent(in) :: lbls(:)
allocate(test_t::t)
t%label = lbls(1)
end subroutine make_test
subroutine make_test2(t,lbls)
class(test_t), allocatable :: 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), allocatable :: p
procedure(if_make_test), pointer :: mt
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)
end program test还有一点:模块级的隐式none语句是由模块过程“继承”的,因此不必在每个子例程中额外地发出它。
https://stackoverflow.com/questions/14899268
复制相似问题