Имейте функцию в 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 является переменной" немного более понятно. Это, однако, более доступный документ и жизнеспособная альтернатива.