gpt4 book ai didi

pointers - Fortran2003:指向函数的过程指针返回指向多态类型的指针

转载 作者:行者123 更新时间:2023-12-03 14:45:54 24 4
gpt4 key购买 nike

对于一个新项目,我正在考虑使用 Fortran2003 的面向对象功能。我尝试过的一件事涉及指向一个函数(不是子例程)的过程指针,该函数返回一个指向多态类型的指针。我想知道这样的构造是否合法,因为我从不同的编译器得到混合结果(见下文)。

作为一个具体的例子,考虑下面的函数接口(interface):

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

并且使用代码应该有一个过程指针,可以指向具有此接口(interface)的函数:
procedure(if_new_test),pointer :: nt

我在问这是否合法,因为 gfortran (4.7.2) 提示此过程指针声明并带有以下消息:

Error: CLASS variable 'nt' at (1) must be dummy, allocatable or pointer



我不明白这个错误信息,如 nt本身就是一个指针,它指向的函数返回的也是一个指针。

作为引用,示例的完整源代码如下。拳头,包含我的派生类型、接口(interface)和函数/子例程的模块:
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_testmake_test2 ,并且在我的测试中,这适用于我尝试过的所有编译器。接下来直接调用 创建对象功能 new_testnew_test2 ,这也适用于我的测试。最后,对象应该再次通过这些函数创建,但间接通过过程指针 nt创建。 .

如上所述,gfortran (4.7.2) 不编译 nt 的声明。 .

ifort (12.0.4.191) 在 nt => new_test 行产生内部编译器错误.

pgfortran (12.9) 在没有警告的情况下编译,并且可执行文件产生预期的结果。

那么,根据 Fortran2003,我试图做的事情是非法的,还是编译器对这些功能的支持仍然不足?我应该只使用子程序而不是函数(因为这似乎有效)?

最佳答案

您的代码似乎很好。我可以用 Intel 13.0.1 和 NAG 5.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 语句由模块过程“继承”,因此您不必在每个子例程中额外发出它。

关于pointers - Fortran2003:指向函数的过程指针返回指向多态类型的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14899268/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com