Fortran function returns a reference that can be placed on the left side of the job

As the name suggests, I want to directly modify the data I am accessing with a pointer obtained from a function. Having a reference returned by a function appearing on lhs assignment (=) is not a problem in C ++, but the following minimal example of fortran errors:

module test_mod
  implicit none

  integer, target :: a=1, b=2, c=3 ! some member variables

contains

  function get(i)
    integer, pointer :: get
    integer, intent(in) :: i

    select case (i)
      case (1)
        get => a
      case (2)
        get => b
      case (3)
        get => c
    end select 
  end function get

end module test_mod

program test
  use test_mod
  implicit none
  integer, pointer :: i_p

  !> prints out 1 2 3
  print*, get(1), get(2), get(3)

  !> this is what I want but I get the error
  !> Error: 'get' at (1) is not a variable
  get(2) = 5

  !> this works but is not what I want
  i_p => get(2)
  i_p = 5

end program test

      

Is there a way to accomplish this behavior; maybe I am missing some attributes? I would like to bypass the entries of any setter routines such as

set(i,value)

      

as it should mimic the appearance of an array. In my application, member variables a,b,c

are actually arrays of different sizes

a = [a1, a2, a3]
b = [b1, b2]
c = [c1]

      

and I want the getter to get(i,j)

simulate a matrix of pointers

        j = 1   2   3

i = 1:   [[a1, a2, a3],
i = 2:    [b1, b2, XX],
i = 3:    [c1, XX, XX]]

      

wehre XX

will link to null()

.

Update: I am using gfortran (version 5.2.0) and the deployment machines will only have versions 4.6.x and up. Therefore the proposed fortran 2008 features are unfortunately not available to me. Is it possible to simulate the above behavior without having a compiler supporting it out of the box?

Update 2: So I ended up implementing the struct like this

type Vec_t
  integer, allocatable, dimension(:) :: vec
end type Vec_t
type(Vec_t), allocatable, dimension(:), target :: data

      

which I initialize as follows (my triangular matrix application which I mention at the end)

allocate(data(max))
do i=1,max
  allocate(data(i)%vec(i))
end do

      

and I access it via

print*, data(2)%vec(1)
data(2)%vec(1) = 5

      

which is not what I was but good enough for my application.

+3


source to share


1 answer


See what you want to do:

get(2)=5

      

and the error message

Error: 'get' at (1) is not a variable

It looks pretty overwhelming: you can't do what you want. Or maybe ...

get(2)

indeed, by Fortran 2003 rules, not a variable. In Fortran 2003, a variable is specified by rules R601 and R603, which are a list of designators.

The left side of the assignment should be a variable.

But look at Fortran 2008 and its variable definition. Now the variable is either one of the same notation (or related to coarrays or complex parts), but can also (C602 - R602) be a reference to a function that



must have the result of a data pointer.

This is summarized in the introduction to Fortran 2008, which details extensions from Fortran 2003 as

A pointer function reference can denote a variable in any variable definition context.

get(2)

is a function reference that has the result of a data pointer. get(2)

then may appear on the left side of an assignment statement according to Fortran 2008 rules.

Alas, this Fortran interpretation is not supported by widespread compilers: at the time of answering the Cray compiler.

This means that this answer really says that you have two options: change the compiler or wait for this feature to become more common. Since both of them are probably impractical, you probably need another answer that provides something more portable as a workaround.

I prefer to refer to that provided innoSPG, since although the latter is based on the first, a description of the relevant field "pointer function - pointer ref - a variable" a little clearer. It is, however, a more accessible document and a viable alternative.

+4


source







All Articles