问题
I would like to program some procedure that will work with different types. I am planning to use the "include" method used in flibs described here and here. I give here a simple exemple.
! -------------------------------------------------------------- !
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
with the included file:
contains
subroutine printme(a)
implicit none
type(T) :: a
print *,a
end subroutine printme
What bothers me is that it seems only to work with derived type, and not with intrinsic types. If the user of the module mod want to use the printme routine on an simple integer, it is really annoying for him to encapsulate it in a ivalue type and cannot doing:
integer :: a=42
call printme(a)
Is there any way to extend this method to intrinsic types, or another method that would do it in strict f90/f95 (I don't want to use the "transfer" method because of the data copy)
Tanks!
回答1:
You can use the C preprocessor (CPP) in all major Fortran compilers. Usually there is a flag for invoking it (-cpp
in gfortran) or it is invoked automatically if the file suffix contains capital F (.F90
, .F
). The preprocessor allows more powerful inclusion of sources with the usage of macros.
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
and template.f90
contains
subroutine printme(a)
implicit none
T :: a
print *,a
end subroutine printme
This is not strict f90 / f95, but it uses a preprocessor, included in the compilers, which produces another (strict f95) source file and it automatically compiles it instead of the original source that contains the macros.
The compilation is then straightforward
gfortran -cpp main.f90
--Edit--
For non-believers, if you want to see some real code using this, check https://github.com/LadaF/fortran-list (disclaimer: my own code). You can use the parametric linked list there as:
list of len(20) character strings:
module str_list
#define TYPEPARAM character(20)
#include "list-inc-def.f90"
contains
#include "list-inc-proc.f90"
#undef TYPEPARAM
end module
list of integers
module int_list
#define TYPEPARAM integer
#include "list-inc-def.f90"
contains
#include "list-inc-proc.f90"
#undef TYPEPARAM
end module
list of some derived type
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
回答2:
You can use implicit typing. Make sure you wash your hands though - as this opens the possibility for the usual errors associated with implicit typing.
Consider a replacement for your module imod.
module imod
use data_type ! oops - I forgot this.
implicit type(itype) (q)
contains
include 'template.f90'
end module imod
(I've moved the contains statement into the including module - as it then allows you to have more than one templated include file.)
and then a procedure in included file that looks like:
! Assume anything starting with q is the type to be templated.
subroutine printme(q_arg)
print *, q_arg
end subroutine printme
If you wanted to template printme for an intrinsic type, then you just change the implicit statement in the parent module appropriately.
It's debatable, but there's also the view that you can use the module renaming facility to introduce new names for intrinsic types. If so, and if you have a F2008 compiler (so we aren't talking strict F95) then your current approach should still be able to work - using an intermediate module to allow renaming of the intrinsic integer type to have a name T.
But this confuses most (all?) compilers I've used in some way. Given that, plus the debatable legality, plus it requiring F2008, it's not a real solution.
来源:https://stackoverflow.com/questions/24064633/how-to-make-some-generic-programming-in-fortran-90-95-working-with-intrinsic-typ