Have a function in fortran return a reference that can be placed on the left-hand-side of an assignment

拥有回忆 提交于 2019-12-07 17:40:38

问题


As stated in the title, I want to directly modify data that I access through a pointer retrieved from a function. Having a reference returned by a function appearing on the l.h.s. of an assignment(=) is no issue in C++ but the following minimal example in fortran errors out:

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 any way to accomplish this behaviour; maybe I'm missing some attributes? I would like to bypass writing any setter routines such as

set(i,value)

since it should mimic the appearance of an array. In my application, the member variables a,b,c are actually arrays of different size

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

and I want the getter get(i,j) to mimic 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 would be referencing to null().

Update: I am using gfortran (version 5.2.0) and the deployment machines would have only versions starting from 4.6.x and upwards. Therefore, the suggested fortran 2008 standard features are unfortunately not available to me. Is it possible to mimic the behaviour described above without having a compiler supporting it out of the box?

Update 2: So I ended up implementing a structure as follows

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

which I initialise like this (my triangular matrix application I mention at the end)

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

and I access & write to it through

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

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


回答1:


Let's look at what you want to do:

get(2)=5

and the error message

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

That looks pretty comprehensive: you can't do what you want. Or, perhaps...

get(2) is indeed, under the rules of Fortran 2003, not a variable. In Fortran 2003 a variable is given by the rules R601 and R603, which is a list of designators.

The left-hand side of an assignment must be a variable.

But look at Fortran 2008 and its definition of a variable. Now a variable is either one of those same designators (or ones related to coarrays or complex parts), but it could also (C602 to R602) be a function reference which

shall have a data pointer result.

This is summarized in the introduction of Fortran 2008, detailing the extensions over Fortran 2003, as

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

get(2) is a reference to a function that has a data pointer result. get(2) then may appear on the left-hand side of an assignment statement under the rules of Fortran 2008.

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

This means that this answer is really saying that you have two options: switch compiler or wait until this feature is more widespread. As both of these are likely impractical, you probably want another answer which gives something slightly more portable as a workaround.

I prefer my link to that given by innoSPG, as although this latter is based on the former, the description of the appropriate field "Pointer functions - pointer function ref is a variable" is slightly more clear. This is, though, a more accessible document and a viable alternative.



来源:https://stackoverflow.com/questions/31570274/have-a-function-in-fortran-return-a-reference-that-can-be-placed-on-the-left-han

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!