PeMa
PeMa

Reputation: 1696

Generic name for distinguishable pointers

Is it possible to use the same generic name for two pointers of different type? The following of course doesn't work, but it should make clear what I mean:

real(4), pointer :: s_p
real(8), pointer :: d_p
generic :: p => s_p,d_p

For procdures these things can be done with interfaces defining destinguishable procedures as module procedure and for type bound procedures there exists the generic type that is used similar to the given example. So I wonder if something like this exists for pointers too.

I'd like to mention that unlimited polymorphic pointers (class(*)) are probably not what I want, since I'm trying to generalize an existing library to double precision input, thus I'd have a lot more work in implementing the select type blocks than just defining two pointers everywhere.

EDIT:

It is of course possible to associate the same pointer with variables of different type/kind. Just some examples:

program test

   implicit none
   real(4),target :: a
   real(8),target :: b
   class(*),pointer :: p

   a=2e0
   b=3d0

   p=>a
   call printer(p)
   a=a+4e0
   call printer(p)
   p=>b
   call printer(p)

   associate (u=>a)       ! for me it's still a miracle why this even works
      print*,u
      a=a+3e0
      print*,u
   end associate
   associate (u=>b)
      print*,u
   end associate

contains

   subroutine printer(p)

      class(*),pointer :: p

      select type (p) 
      type is (real(4))
         p=p+2d0              ! even the wrong 2d0 gets converted correctly
         print*,p
      type is (real(8))
         print*,p
      end select

   end subroutine

end program

My problem with this solution is that I would have to implement select type blocks everywhere in the library where the pointer is used. (At the moment I only know that it's many places.)

So the main problem is that the unlimited polymorphic pointer (p in the example) stays polymorphic unless it is used inside a select type environement. This is of course necessary, since the pointer could be everything. So the actual question is: Is there a possibility to tell the polymorphic pointer in advance: You can only be either this or that (e.g real(4) or real(8)) and depening on what it is associated to, it knows what it is?

The answer is probably no, but at the moment I don't really see, in which situtation the compliler might have problems to distinguish between types/kinds.

Upvotes: 0

Views: 67

Answers (2)

IanH
IanH

Reputation: 21431

No. A data pointer is a variable. You cannot have two different variables with the same name accessible in the same scope.

If you hypothetically could... in many cases the compiler would have no way of knowing which variable you meant when that common name appeared.

The situation for generic procedure names is different - the compiler can resolve which specific procedure is relevant when a generic procedure name is referenced by examining the number, types, kinds and ranks of the arguments in the procedure reference. The rules of the language ensure that there can only be at most one such matching specific procedure, and that generic procedure names do not appear in contexts where the ability to resolve the relevant specific procedure is not possible.

Upvotes: 1

Alexander Vogt
Alexander Vogt

Reputation: 18098

No, this is not possible. Clause C714 (R733) from the Fortran 2008 Standard states:

If data-target is not unlimited polymorphic, data-pointer-object shall be type compatible (4.3.1.3) with it and the corresponding kind type parameters shall be equal.

You could, however, put the corresponding code in its own file, and include it with a different kind variable in place:

common.inc.F90:

real(KINDVAR), pointer :: p

contains

function fun1(x) result(res)
  real(KINDVAR) :: x, res
  ! ...
end function

module_double.F90:

module test_double
  use,intrinsic :: ISO_Fortran_env, only: REAL64
  integer,parameter :: KINDVAR = REAL64

  include 'common.inc.F90'
end module

module_single.F90:

module test_single
  use,intrinsic :: ISO_Fortran_env, only: REAL32
  integer,parameter :: KINDVAR = REAL32

  include 'common.inc.F90'
end module

Then you can include the different modules, and even rename the subroutines on-the-fly:

use test_single only: fun1_sgl => fun1, p_sgl => p
use test_double only: fun1_dbl => fun1, p_dbl => p

This is called "Poor man's templates" and was published here.

Upvotes: 1

Related Questions