come scrivere wrapper per ‘allocare’

Sto cercando di scrivere un wrapper per la funzione ‘allocate’, cioè la funzione che riceve una matrice e le dimensioni, alloca la memoria e restituisce la matrice allocata. La cosa più importante è che la funzione deve funzionare con array di rango diverso. Ma devo dichiarare esplicitamente il rank dell’array nell’interfaccia di funzione, e in questo caso il codice viene compilato solo se si passano array di determinati rank come parametro. Ad esempio, questo codice non viene compilato:

module memory_allocator contains subroutine memory(array, length) implicit none real(8), allocatable, intent(out), dimension(:) :: array integer, intent(in) :: length integer :: ierr print *, "memory: before: ", allocated(array) allocate(array(length), stat=ierr) if (ierr /= 0) then print *, "error allocating memory: ierr=", ierr end if print *, "memory: after: ", allocated(array) end subroutine memory subroutine freem(array) implicit none real(8), allocatable, dimension(:) :: array print *, "freem: before: ", allocated(array) deallocate(array) print *, "freem: after: ", allocated(array) end subroutine freem end module memory_allocator program alloc use memory_allocator implicit none integer, parameter :: n = 3 real(8), allocatable, dimension(:,:,:) :: foo integer :: i, j, k print *, "main: before memory: ", allocated(foo) call memory(foo, n*n*n) print *, "main: after memory: ", allocated(foo) do i = 1,n do j = 1,n do k = 1, n foo(i, j, k) = real(i*j*k) end do end do end do print *, foo print *, "main: before freem: ", allocated(foo) call freem(foo) print *, "main: after freem: ", allocated(foo) end program alloc 

Errore di compilazione:

 gfortran -o alloc alloc.f90 -std=f2003 alloc.f90:46.14: call memory(foo, n*n*n) 1 Error: Rank mismatch in argument 'array' at (1) (1 and 3) alloc.f90:60.13: call freem(foo) 1 Error: Rank mismatch in argument 'array' at (1) (1 and 3) 

C’è un modo per implementare tale wrapper? ..

Grazie!

Questo può essere fatto tramite un blocco di interfaccia generico. Devi creare procedure per ogni grado che vuoi gestire, ad esempio, memory_1d, memory_2d, … memory_4d. (Ovviamente un sacco di tagliare e incollare.) Quindi si scrive un blocco di interfaccia generico che dà a tutte queste procedure la memoria del nome alternativo come nome di una procedura generica. Quando si chiama memoria, il compilatore distingue quale memoria_Xd dovrebbe essere chiamata in base al rango dell’argomento. Lo stesso per le tue funzioni freem.

Questo è il modo in cui funzioni intrinseche come il peccato hanno funzionato a lungo – si può chiamare il peccato con argomenti reali di varie previsioni, o con un argomento complesso, e il compilatore calcola con la funzione del peccato reale da chiamare. Nel FORTRAN molto vecchio dovevi usare nomi diversi per le diverse funzioni sin. Ora Fortran moderno è ansible impostare la stessa cosa con le proprie routine.

Modifica: aggiunta di un esempio di codice che dimostra il metodo e la syntax:

 module double_array_mod implicit none interface double_array module procedure double_vector module procedure double_array_2D end interface double_array private ! hides items not listed on public statement public :: double_array contains subroutine double_vector (vector) integer, dimension (:), intent (inout) :: vector vector = 2 * vector end subroutine double_vector subroutine double_array_2D (array) integer, dimension (:,:), intent (inout) :: array array = 2 * array end subroutine double_array_2D end module double_array_mod program demo_user_generic use double_array_mod implicit none integer, dimension (2) :: A = [1, 2] integer, dimension (2,2) :: B = reshape ( [11, 12, 13, 14], [2,2] ) integer :: i write (*, '( / "vector before:", / 2(2X, I3) )' ) A call double_array (A) write (*, '( / "vector after:", / 2(2X, I3) )' ) A write (*, '( / "2D array before:" )' ) do i=1, 2 write (*, '( 2(2X, I3) )' ) B (i, :) end do call double_array (B) write (*, '( / "2D array after:" )' ) do i=1, 2 write (*, '( 2(2X, I3) )' ) B (i, :) end do stop end program demo_user_generic 

subroutine memory(array, length) ha come prima matrice dummy monodesmensionale ( real(8), allocatable, intent(out), dimension(:) :: array ).

Chiamando questa subroutine dal tuo programma principale con array foo tridimensionale ( real(8), allocatable, dimension(:,:,:) :: foo ) è ovviamente un errore. E questo è ciò che effettivamente ha detto il compilatore.

Se hai veramente bisogno di tali subroutine, scrivi una coppia di subroutine di memory / freem per ogni array di dimensioni diverse: una coppia di subroutine per l’array 1-dimensionale, l’altra per l’array bidimensionale, ecc.

A proposito, memory subroutine di memory saranno diverse in generale, perché per allocare un array n-dimensionale è necessario passare n estensioni alla suddetta subroutine.