2010-02-13 14 views
8

Ich versuche, einen Wrapper für "allocate" -Funktion zu schreiben, d. H. Funktion, die ein Array und Dimensionen erhält, Speicher reserviert und zugewiesenes Array zurückgibt. Das Wichtigste ist, dass die Funktion mit Arrays unterschiedlichen Ranges arbeiten muss. Aber ich muss explizit den Rang des Arrays in der Funktionsschnittstelle angeben, und in diesem Fall kompiliert der Code nur, wenn ich Arrays bestimmten Rangs als Parameter übergebe. Zum Beispiel ist dieser Code nicht kompilieren:Wie Wrapper für "allocate" schreiben

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 

Übersetzungsfehler:

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) 

Gibt es eine Möglichkeit, solche Wrapper zu implementieren ..

Dank!

Antwort

10

Dies kann über einen generischen Schnittstellenblock erfolgen. Sie müssen Prozeduren für jeden Rang erstellen, den Sie behandeln möchten, z. B. memory_1d, memory_2d, ... memory_4d. (Offensichtlich eine Menge Schnitt & Einfügen.) Dann schreiben Sie einen generischen Schnittstellenblock, der all diesen Prozeduren den alternativen Namensspeicher als generischen Prozedurnamen gibt. Wenn Sie Speicher aufrufen, unterscheidet der Compiler, welcher memory_Xd basierend auf dem Rang des Arguments aufgerufen werden soll. Das Gleiche gilt für Ihre Freem-Funktionen.

Dies ist, wie intrinsische Funktionen wie Sünde lange gearbeitet haben - Sie können Sünde mit einer realen Argumente verschiedener Previse oder mit einem komplexen Argument aufrufen, und der Compiler mit tatsächlichen sin Funktion zu nennen. In wirklich altem FORTRAN mussten Sie verschiedene Namen für die verschiedenen sin Funktionen verwenden. Jetzt modernen Fortran können Sie das gleiche mit Ihren eigenen Routinen einrichten.

Edit: Hinzufügen eines Codebeispiel wird die Methode & Syntax demonstriert:

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 
+0

Vielen Dank! Obwohl es Code-Duplizierung im Zuordnungsmodul erfordert, kann ich zumindest den allgemeinen Namen verwenden, wenn ich diese Zuweisungsfunktion aufruft. Das ist was ich wollte. – robusta

1

subroutine memory(array, length) hat als erste Dummy-Parameter 1-dimensionale Array (real(8), allocatable, intent(out), dimension(:) :: array).

Aufruf dieser Subroutine von Ihrem Hauptprogramm mit 3-dimensionalen Array foo (real(8), allocatable, dimension(:,:,:) :: foo) ist offensichtlich Fehler. Und das ist was der Compiler eigentlich gesagt hat.

Wenn Sie wirklich brauchen solche Subroutinen ein Paar memory/freem Subroutinen für jede Reihe unterschiedlicher Dimension schreiben - ein Subroutinen Paar für 1-dimensionale Anordnung, eine andere für 2-dimensionalen Array usw.

By the way, memory Unterroutinen werden im Allgemeinen anders sein, weil, um ein n-dimensionales Array zuzuteilen, n Extents an das oben erwähnte Unterprogramm übergeben werden müssen.

+0

kemiisto, ich verstehe, dass diese Compiler-Fehler absolut offensichtlich ist. Ich verstehe auch, dass eine Art zu implementieren, was ich will, separate Zuweiser für verschiedene Ränge schreiben. Ich werde dies als letztes Mittel tun müssen :) Aber meine Frage war - gibt es eine legitime fortran Weise, einen Wrapper zu schreiben, um mit SAME Funktionalität zuzuordnen, d. H. Universal wrt rank ... Danke trotzdem! – robusta