Как создать универсальную подпрограмму для работы в fortran с массивом предполагаемого размера

#arrays #fortran90 #generic-programming

#массивы #fortran90 #generic-программирование

Вопрос:

У меня есть блок интерфейса для определения универсальной подпрограммы, которая имеет массив предполагаемого размера в качестве фиктивного аргумента (чтобы иметь возможность воздействовать на «середину» переданного массива, например, указатель C), и он не компилируется. Вот простой пример:

 module foo

  interface sub
     module procedure isub
     module procedure dsub
  end interface

  contains

  subroutine isub(a,n)
    integer, intent(in) :: a(*), n
    integer :: i
    print*, 'isub'
    do i=1,n
     print*, a(i)
    enddo
  end subroutine isub

  subroutine dsub(a)
    real(8), intent(in) :: a(*)
    integer, intent(in) :: n
    integer :: i
    print*, 'dsub'
    do i=1,n
     print*, a(i)
    enddo
  end subroutine dsub

end module foo

program test

  use foo

  implicit none

  integer :: ai(4)
  real(8) :: ad(4)

  ai=(/1,2,3,4/)
  ad=(/1.,2.,3.,4./)

  call sub(ai,3)
  call sub(ad,3)

  call isub(ai(2),3)
  !call sub(ai(2),3)

end program test
  

Закомментированная строка не компилируется, тогда как это нормально при непосредственном вызове подпрограммы с call isub(ai(2),3) помощью (проверено с помощью gfortran и ifort). Почему и возможно ли с ней работать call sub(ai(2),3) ?

редактировать: с помощью ifort в нем говорится:

 $ ifort overload.f90
overload.f90(37): error #6285: There is no matching specific subroutine for this generic subroutine call.   [SUB]
  call sub(ai(2),3)
-------^
compilation aborted for overload.f90 (code 1)
  

Спасибо

Ответ №1:

Вы передаете скаляр функции, которая ожидает массив. Попробуйте

 call sub(ai(2:2))
  

которая передает массив длиной один. Мне интересно, почему call isub(ai(2)) это принято…

Чтобы ответить на ваш новый вопрос (частично в комментариях):

Если вы ограничиваетесь непрерывными массивами, вы можете использовать call sub(ai(2:4)) без потери производительности использование отложенных массивов формы:

 subroutine isub(a)
  integer,intent(in) :: a(:)
  integer            :: i

  print*, 'isub'
  do i=1,size(a)
    print*, a(i)
  enddo
end subroutine isub
  

Временных массивов, созданных с ifort помощью or, нет gfortran . Вы можете проверить это с помощью:

  • ifort -check arg_temp_created

  • gfortran -Warray-temporaries

Комментарии:

1. Мой пример был не очень хорош (я его сейчас отредактировал), но в моем реальном приложении я не хочу передавать ни одного элемента, кроме адреса любого элемента массива вызывающего, из которого подпрограмма начнет обрабатывать, как я бы сделал с указателем C. И я не хочу использовать фрагменты, которые включают временную копию

2. Почему? Вы программируете на Fortran, а не на C ?!

3. Вы пытаетесь написать подпрограмму для массивов разных размеров (например, векторов и матриц)?

4. Вы знаете, что Fortran обычно передает аргументы по ссылке, верно? Нет необходимости в указателях на то, чего (я думаю) вы пытаетесь достичь…

5. Да, я знаю. При создании call sub(ai(2),3)) я просто хочу передать подпрограмме isub адрес или ссылку на второй элемент ai. И я не хочу использовать предполагаемый массив формы в подпрограммах из-за проблем с производительностью (и я не могу использовать НЕПРЕРЫВНЫЙ атрибут, потому что я застрял в f95). Но это не работает…