2016-05-09 6 views
1

Целью является создание единой процедуры распределения, которая может обрабатывать распределение одного ранга одного типа. Затем наша библиотека кода может иметь один вызов со стандартизованным захватом ошибок.Процедура распределения полиморфных массивов в Fortran

Ошибка компилятора следующим образом:

generic_allocation.f08:32:27: 

     call myAllocator (array_int, source_int, lambda) 
          1 
Error: Actual argument to ‘myarray’ at (1) must be polymorphic 
generic_allocation.f08:33:27: 

     call myAllocator (array_real, source_real, lambda) 
          1 
Error: Actual argument to ‘myarray’ at (1) must be polymorphic 

Может ли этот код исправить?

Тест код пытается выделить целочисленный массив, а затем реальный массив:

module mAllocator 
    implicit none 
contains 
    subroutine myAllocator (myArray, source_type, lambda) 
     class (*), allocatable, intent (inout) :: myArray (:) 
     class (*),    intent (in) :: source_type 
     integer,     intent (in) :: lambda 

     integer     :: alloc_status = 0 
     character (len = 512) :: alloc_message = '' 
      allocate (myArray (1 : lambda), source = source_type, stat = alloc_status, errmsg = alloc_message) 
      if (alloc_status /= 0) then 
       write (*, "(' allocation errmsg = ', g0, '.')") trim (alloc_message) 
       stop 'Fatal error in subroutine myAllocator' 
      end if 
    end subroutine myAllocator 
end module mAllocator 

program generic_allocation 

    use mAllocator, only : myAllocator 

    implicit none 

    integer, parameter :: lambda = 10 
    integer, parameter :: source_int = 1 
    real, parameter :: source_real = 1.0 

    integer, allocatable :: array_int (:) 
    real, allocatable :: array_real (:) 
     call myAllocator (array_int, source_int, lambda) 
     call myAllocator (array_real, source_real, lambda) 
end program generic_allocation 

Первая версия кода полагались на платформе select type конструкции, как показано на FORTRAN: polymorphism allocation. Другая используемая ссылка - Fortran polymorphism, functions and allocation.

gfortran версия 6,0

$ gfortran -v 
Using built-in specs. 
COLLECT_GCC=gfortran 
COLLECT_LTO_WRAPPER=/opt/gnu/6.0/libexec/gcc/x86_64-pc-linux-gnu/6.0.0/lto-wrapper 
Target: x86_64-pc-linux-gnu 
Configured with: ./configure --prefix=/opt/gnu/6.0 --enable-languages=c,c++,fortran,lto --disable-multilib --disable-werror 
Thread model: posix 
gcc version 6.0.0 20160227 (experimental) (GCC) 
+2

* Цель состоит в том, чтобы создать единую процедуру распределения, которая может обрабатывать любое распределение рангов одного уровня. * Разве это не означает, что 'allocate' предоставляет? –

ответ

4

Вы столкнулись осознанное ограничение на языке, поставить на место, чтобы предотвратить процедуру от выделения объекта к некоторому типу, который не соответствует заявленному типу фактического аргумент. Подумайте, что произойдет, если ваш распределитель выделил фиктивный аргумент, соответствующий array_int, типа REAL.

Вы не можете достичь своей цели с помощью одной процедуры, однако вы можете уйти с написанием одного фрагмента исходного кода, после чего ВКЛЮЧАЙТЕ в тело нескольких процедур, по одному для каждого объявленного типа (и вида), с которым вы хотите иметь дело.

! In AllocateBody.i90 
integer, intent(in) :: lambda 
integer     :: alloc_status 
character (len = 512) :: alloc_message 
allocate (myArray (1 : lambda), & 
    source = source_type, & 
    stat = alloc_status, & 
    errmsg = alloc_message) 
if (alloc_status /= 0) then 
    write (*, "(' allocation errmsg = ', g0, '.')") & 
     trim (alloc_message) 
    stop 'Fatal error in subroutine myAllocator' 
end if  


! Elsewhere. 
subroutine my_allocator_integer(myArray, source_type, lambda) 
    integer, intent(out), allocatable :: myArray(:) 
    integer, intent(in) :: source_type 
    include 'AllocateBody.i90' 
end subroutine my_allocator_integer 

subroutine my_allocator_real(myArray, source_type, lambda) 
    real, intent(out), allocatable :: myArray(:) 
    real, intent(in) :: source_type 
    include 'AllocateBody.i90' 
end subroutine my_allocator_real 

subroutine my_allocator_foo(myArray, source_type, lambda) 
    type(foo), intent(out), allocatable :: myArray(:) 
    type(foo), intent(in) :: source_type 
    include 'AllocateBody.i90' 
end subroutine my_allocator_foo 

Вы можете поместить все эти конкретные процедуры за одним общим именем.

Однако, прежде чем приступать к этому, обратите внимание на то, что в современном Фортране выделяемые предметы могут быть выделены даже без инструкции ALLOCATE - простое присвоение переменной allocatable может привести к ее распространению. У вас нет способа обработки сообщений об ошибках для этих случаев. Существует также очень большое количество конструкций кодирования, которые приведут к тому, что компилятор «выделяет» память на свои собственные внутренние потребности, что опять же не позволяет обрабатывать ошибки. На более низком уровне, так как операционные системы действительно выполняют запросы по программе для памяти, также работает против вас - система может быть перегружена, и недостаточная ошибка памяти не может быть сообщена операционной системой процессу до тех пор, пока не будет выделено заявление завершено. В сочетании, в ситуации, когда доступная память очень низкая, и попытка выделить небольшой объект потерпела неудачу, возможно, что для компилятора недостаточно памяти, чтобы даже выполнить код сообщения об ошибках. Также существует проблема, что во время выполнения компилятора лучше понять причины сбоя и состояние программы, которую он может связывать с помощью простого целочисленного кода и символьного сообщения - например, время выполнения компилятора может дать пользователю трассировку стека или аналогичный, в дополнение к любому сообщению, которое он мог бы передать в программу обратно.

Все, для небольших ассигнований программист предоставил сообщение об ошибке, возможно, не очень продуктивным.

Это может быть очень полезно для больших распределений, где вероятность конкретного сбоя выше, и очень вероятно, что причина может быть успешно передана и принята («Ваше измерение проблемы слишком велико! попробуйте еще раз ... ").