Имейте функцию в fortran, возвращающую ссылку, которая может быть помещена на левой стороне назначения

Как указано в заголовке, я хочу напрямую изменить данные, к которым у меня есть доступ через указатель, полученный из функции. Наличие ссылки, возвращаемой функцией, появляющейся в lhs присваивания (=), не является проблемой в C++, но следующий минимальный пример ошибок fortran:

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

Есть ли способ выполнить это поведение; может быть, мне не хватает некоторых атрибутов? Я хотел бы обойти написание любых процедур сеттера, таких как

set(i,value)

так как это должно имитировать внешний вид массива. В моем приложении переменные-члены a,b,c на самом деле массивы разного размера

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

и я хочу добытчик get(i,j) имитировать матрицу указателей

        j = 1   2   3

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

wehre XX будет ссылаться на null(),

Обновление: я использую gfortran (версия 5.2.0), и машины развертывания будут иметь только версии, начиная с 4.6.x и выше. Поэтому предлагаемые стандартные функции Fortran 2008, к сожалению, мне недоступны. Можно ли имитировать поведение, описанное выше, не имея компилятора, поддерживающего его из коробки?

Обновление 2: Итак, я реализовал структуру следующим образом

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

который я инициализирую, как это (мое приложение треугольной матрицы я упоминаю в конце)

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

и я получаю доступ и пишу через

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

что не совсем то, что я был после, но достаточно хорошо для моего приложения.

1 ответ

Решение

Давайте посмотрим, что вы хотите сделать:

get(2)=5

и сообщение об ошибке

Ошибка: 'get' в (1) не является переменной

Это выглядит достаточно всеобъемлющим: вы не можете делать то, что вы хотите. Или, может быть...

get(2) действительно, по правилам Fortran 2003, не является переменной. В Fortran 2003 переменная задается по правилам R601 и R603, которая представляет собой список обозначений.

Левая часть присваивания должна быть переменной.

Но посмотрите на Fortran 2008 и его определение переменной. Теперь переменная является одним из тех же обозначений (или относящихся к грубым или сложным деталям), но она также может (C602 - R602) быть ссылкой на функцию, которая

должен иметь результат указателя данных.

Это кратко изложено во введении Fortran 2008, детализируя расширения над Fortran 2003, а

Ссылка на функцию указателя может обозначать переменную в любом контексте определения переменной.

get(2) является ссылкой на функцию, которая имеет результат указателя данных. get(2) затем может появиться в левой части оператора присваивания в соответствии с правилами Fortran 2008.

Увы, эта интерпретация Fortran широко не поддерживается нынешними компиляторами: на момент ответа только компилятор Cray.

Это означает, что этот ответ действительно говорит о том, что у вас есть два варианта: переключить компилятор или подождать, пока эта функция не станет более распространенной. Поскольку оба они, вероятно, нецелесообразны, вам, вероятно, нужен другой ответ, который дает что-то более портативное в качестве обходного пути.

Я предпочитаю свою ссылку на ссылку , предоставленную innoSPG, поскольку, хотя последняя основана на первом, описание соответствующего поля "Функции указателя - функция указателя ref является переменной" немного более понятно. Это, однако, более доступный документ и жизнеспособная альтернатива.

Другие вопросы по тегам