如何为'allocate'编写包装 [英] how to write wrapper for 'allocate'
问题描述
我想为'allocate'函数编写一个包装器,即接收数组和维的函数,分配内存并返回分配的数组。最重要的是该函数必须适用于不同级别的数组。但是我必须在函数接口中明确声明数组的等级,并且在这种情况下,如果我将特定等级的数组作为参数传递,则代码仅进行编译。例如,这段代码不会编译:
I am trying to write a wrapper for 'allocate' function, i.e. function which receives an array and dimensions, allocates memory and returns allocated array. The most important thing is that the function must work with arrays of different rank. But I have to explicitly state rank of array in function interface, and in this case code only compiles if I pass arrays of certain rank as a parameter. For example, this code does not compile:
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
编译错误:
Compilation error:
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)
参数'array'中排名不匹配有没有这种包装的实现方式是什么?..
Is there any way of implementing such wrapper?..
谢谢!
Thanks!
推荐答案
这可以通过通用接口模块来完成。您必须为要处理的每个等级创建过程,例如memory_1d,memory_2d,... memory_4d。 (很明显,很多剪切和粘贴)。然后你编写一个通用接口块,将所有这些过程的替代名称存储器作为通用过程名称。当你调用内存时,编译器根据参数的等级来区分应该调用哪一个memory_Xd。
This can be done via a generic interface block. You have to create procedures for each rank that you want to handle, e.g., memory_1d, memory_2d, ... memory_4d. (Obviously a lot of cut & pasting.) Then you write a generic interface block that gives all of these procedures the alternative name memory as a generic procedure name. When you call memory, the compiler distinguishes which memory_Xd should be called based on the rank of the argument. The same for your freem functions.
这就是sin这样的内在函数长期以来的工作原理 - 你可以用各种预设的真实参数或者用复杂的论点,编译器会用实际的sin函数来调用。在真正旧的FORTRAN中,你必须为不同的sin函数使用不同的名称。现在的Fortran,你可以用自己的例程设置相同的东西。
This is how intrinsic functions such as sin have long worked -- you can call sin with a real arguments of various previsions, or with a complex argument, and the compiler figures out with actual sin function to call. In really old FORTRAN you had to use different names for the different sin functions. Now modern Fortran you can setup the same thing with your own routines.
编辑:添加一个代码示例演示方法&语法:
adding a code example demonstrating the method & 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
这篇关于如何为'allocate'编写包装的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!