Fortran2003: pointer to a function that returns a pointer to a polymorphic type

For a new project, I am considering using Fortran2003 object-oriented features. One thing I tried includes a pointer to a procedure that points to a function (not a subroutine) that returns a pointer to a polymorphic type. I wonder if such a construction is legal, as I get mixed results from different compilers (see below).

As a specific example, consider the following function 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 

And the code used must have a procedure pointer that can point to functions with this interface:

 procedure(if_new_test),pointer :: nt 

I ask if this is legal because gfortran (4.7.2) complains about this pointer declaration of this procedure with the message:

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

I do not understand this error message, since nt itself is a pointer, and the fact that the function points to its return is also a pointer.

For reference, the full source code is provided for an example. Fist, a module containing my derived types, interfaces, and functions / routines:

 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 

And the main program using this module:

 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 

The program first creates objects using the make_test and make_test2 , and in my testing this works with all the compilers I tried. Then the objects are created by directly calling the new_test and new_test2 , which also work in my tests. Finally, objects must be re-created using these functions, but indirectly using the nt procedure pointer.

As stated above, gfortran (4.7.2) does not compile the nt declaration.

ifort (12.0.4.191) creates an internal compiler error in the line nt => new_test .

pgfortran (12.9) compiles without warning, and the executable produces the expected results.

So, what am I trying to make illegal according to Fortran2003, or is compiler support for such functions still insufficient? Should I just use routines instead of functions (how does this work)?

+4
source share
1 answer

Your code looks fine. I could compile it with both Intel 13.0.1 and NAG 5.3.1 without any problems. The old compiler may have problems with the more "bizarre" features of Fortran 2003.

Depending on the problem, you can also use allocatable types instead of pointers. On the other hand, if you have more problems with a memory leak, you cannot return the polymorphic type as a result of the function:

 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 

One more note: the implicit statement none at the module level is โ€œinheritedโ€ by the module procedures, so you do not need to expose it in each additional subroutine.

+1
source

All Articles