我想编写一些适用于不同类型的程序。我打算使用在here和here描述的flib中使用的“include”方法。我在这里给出一个简单的例子。
! -------------------------------------------------------------- !
module data_type
type ivalue
integer :: v
end type
type rvalue
real(8) :: v
end type
end module data_type
! -------------------------------------------------------------- !
module imod
use data_type, only: T => ivalue
include "template.f90"
end module imod
! -------------------------------------------------------------- !
module rmod
use data_type, only: T => rvalue
include "template.f90"
end module rmod
! -------------------------------------------------------------- !
module mod
use imod, only:
& ivalue => T,
& iprintme => printme
use rmod, only:
& rvalue => T,
& rprintme => printme
private
public :: ivalue, rvalue
public :: printme
interface printme
module procedure iprintme
module procedure rprintme
end interface printme
end module mod
! -------------------------------------------------------------- !
program hello
use mod
implicit none
type(ivalue) :: iv
type(rvalue) :: rv
iv%v=42
rv%v=3.14
call printme(iv)
call printme(rv)
end program hello
包含文件:
contains
subroutine printme(a)
implicit none
type(T) :: a
print *,a
end subroutine printme
困扰我的是它似乎只适用于派生类型,而不适用于内在类型。如果模块mod的用户想要在一个简单的整数上使用printme例程,那么将它封装在一个ivalue类型中并且无法做到这一点真的很烦人:
integer :: a=42
call printme(a)
有没有办法将此方法扩展为内部类型,或者在严格的f90 / f95中执行此操作的另一种方法(由于数据复制,我不想使用“transfer”方法)
坦克!
答案 0 :(得分:6)
您可以在所有主要的Fortran编译器中使用C预处理器(CPP)。通常有一个用于调用它的标志(gfortran中为-cpp
),或者如果文件后缀包含大写字母F(.F90
,.F
),则会自动调用它。预处理器允许使用宏来更强大地包含源。
module imod
use data_type, only: ivalue
#define T type(ivalue)
#include "template.f90"
#undef T
end module imod
module intmod
#define T integer
#include "template.f90"
#undef T
end module intmod
和template.f90
contains
subroutine printme(a)
implicit none
T :: a
print *,a
end subroutine printme
这不是 strict f90 / f95,但它使用编译器中包含的预处理器,它会生成另一个(严格的f95)源文件,它会自动编译它而不是包含原始源的文件宏。
编译很简单
gfortran -cpp main.f90
<强> - 编辑 - 强>
对于非信徒,如果你想看到一些使用它的真实代码,请检查https://github.com/LadaF/fortran-list(免责声明:我自己的代码)。您可以在其中使用参数链表:
len(20)个字符串列表:
module str_list
#define TYPEPARAM character(20)
#include "list-inc-def.f90"
contains
#include "list-inc-proc.f90"
#undef TYPEPARAM
end module
整数列表
module int_list
#define TYPEPARAM integer
#include "list-inc-def.f90"
contains
#include "list-inc-proc.f90"
#undef TYPEPARAM
end module
某些派生类型的列表
module new_type_list
use, new_type_module, only: new_type
#define TYPEPARAM type(newtype)
#include "list-inc-def.f90"
contains
#include "list-inc-proc.f90"
#undef TYPEPARAM
end module
答案 1 :(得分:1)
您可以使用隐式输入。确保你洗手 - 因为这打开了与隐式打字相关的常见错误的可能性。
考虑替换你的模块imod。
module imod
use data_type ! oops - I forgot this.
implicit type(itype) (q)
contains
include 'template.f90'
end module imod
(我已将contains语句移动到包含模块中 - 因为它允许您拥有多个模板化包含文件。)
然后是包含文件中的过程,如下所示:
! Assume anything starting with q is the type to be templated.
subroutine printme(q_arg)
print *, q_arg
end subroutine printme
如果您想为内部类型模板printme,那么您只需适当更改父模块中的隐式语句。
这是值得商榷的,但也有一种观点认为您可以使用模块重命名工具为内在类型引入新名称。如果是这样,并且如果你有一个F2008编译器(所以我们不是严格说F95)那么你当前的方法应该仍然能够工作 - 使用一个中间模块允许重命名内部整数类型以具有名称T
但是这会混淆我以某种方式使用的大多数(所有?)编译器。考虑到这一点,再加上有争议的合法性,加上它要求F2008,它不是一个真正的解决方案。
答案 2 :(得分:0)
实现此目的的另一种方法是使用 Python 预处理 Fortran 源代码。在我正在处理的代码中,我们使用 this Python script 来预处理 Fortran 模板。例如,它用于为 MPI 函数编写接口,如下面的 Fortran 代码片段:
module mod_mpi_grid
implicit none
@python ftypes=["integer(2)","integer(4)","integer(8)","real(4)","real(8)","complex(4)","complex(8)","logical"]
@python fsuffixes=["_i2","_i4","_i8","_f","_d","_c","_z","_l"]
@python fsizeof=["2","4","8","4","8","8","16","2"]
@python fmpitypes=["MPI_INTEGER2","MPI_INTEGER","MPI_INTEGER8","MPI_REAL","MPI_DOUBLE_PRECISION","MPI_COMPLEX","MPI_DOUBLE_COMPLEX","MPI_LOGICAL"]
@python ntypes=8
interface mpi_grid_send
@template begin
@template variable fsuffix
@python for i in range(ntypes): fsuffix=fsuffixes[i];
module procedure mpi_grid_send#fsuffix
@template end
end interface
contains
:
@template begin
@template variable fsuffix
@template variable ftype
@template variable fmpitype
@python for i in range(ntypes): fsuffix=fsuffixes[i]; ftype=ftypes[i]; fmpitype=fmpitypes[i];
subroutine mpi_grid_send#fsuffix(val,n,dims,dest,tag)
use mpi
implicit none
! arguments
#ftype, intent(in) :: val
integer, intent(in) :: n
integer, dimension(:), intent(in) :: dims
integer, dimension(:), intent(in) :: dest
integer, intent(in) :: tag
! local variables
integer :: comm, dest_rank, req, ierr
integer :: idims(0:ndmax)
idims = convert_dims_to_internal(dims)
comm = mpi_grid_get_comm_internal(idims)
dest_rank = mpi_grid_rank_internal(comm,idims(0),dest)
call mpi_isend(val,n,#fmpitype,dest_rank,tag,comm,req,ierr)
return
end subroutine mpi_grid_send#fsuffix
@template end
:
end module mod_mpi_grid
然后,在构建时,Makefile
调用以下行将模板预处理为 Fortran 源代码文件以进行编译:
python ftemplate.py < src/addons/mod_mpi_grid.tpl > src/addons/mod_mpi_grid.f90
子例程中 #ftype
的所有实例都被内部类型 integer(2)
、integer(4)
、... logical
替换。因此,这种方法适用于内在类型!
需要通过 MPI 发送数据的其他部分代码只需要 use mod_mpi_grid
和通用子例程 call mpi_grid_send( ... )
。