目标是创建一个可以处理任何类型的一级分配的单个分配例程。然后,我们的代码库可以通过标准化的错误捕获进行单次调用。
编译器错误如下:
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)
答案 0 :(得分: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
您可以将所有这些特定程序放在一个通用名称后面。
但是,在开始之前,请注意在现代Fortran中,即使没有ALLOCATE语句也可以分配可分配的东西 - 对可分配变量的简单赋值可能导致它被分配。您无法处理这些情况的错误消息。还有大量的编码结构会导致编译器为自己的内部需求“分配”内存,同样,你也无法处理错误。在较低级别,操作系统实际满足内存程序请求的方式也对您不利 - 系统可能过度使用,并且操作系统可能无法在分配之后向进程报告内存不足的错误声明已经完成。在组合中,在可用内存非常低并且尝试分配小对象失败的情况下,可能没有足够的内存可供编译器甚至执行错误报告代码。还有一个问题是编译器的运行时更好地了解失败的原因以及它可以通过简单的整数代码和字符消息进行通信的程序状态 - 例如编译器的运行时可以为用户提供堆栈跟踪或类似的,除了它可以传递回程序的任何消息。
总而言之,对于小型分配,程序员提供的错误报告可能效率不高。
对于更大的分配来说非常值得,特定故障的可能性更高,并且很可能成功地传达和采取行动(“你的问题维度太大了!请把它缩小并尝试再次......“)由用户。