My answer is similar to @Fortranner's answer but I usually place the whole implementation inside of an include file.
It has the advantage that multiple procedures could be handled by one single include file and it is easier to maintain, e.g.
you can see the whole procedure's defintion, etc.
Some preprocessor voodoo (see PASTE
, CONCATHELP
, etc.) is needed but it works.
The same example as given by @Fortranner could be written as follows.
The main file main.f90
:
program main
use cumul_m, only: cumul
implicit none
print *, cumul([1, 2, 3 ]) ! output: 1 3 6
print *, cumul([1.1, 2.2, 3.3 ]) ! output: 1.1 3.3 6.6
print *, cumul([1.1d0, 2.2d0, 3.3d0]) ! output: 1.1 3.3 6.6
end program
The module file cumul.f90
:
module cumul_m
use iso_fortran_env, only: real32, real64
implicit none
private
public cumul
interface cumul
module procedure :: cumul_int, cumul_sp, cumul_dp
end interface
contains
#define T int
#define TT integer
#include "cumul_imp.f90.inc"
#define T sp
#define TT real(real32)
#include "cumul_imp.f90.inc"
#define T dp
#define TT real(real64)
#include "cumul_imp.f90.inc"
end module
The implementation's include file cumul_imp.f90.inc
:
#define PASTE(X) X
#define PASTE2(X) PASTE(X)_
#define CONCATHELP(X, Y) PASTE2(X)Y
#define CONCAT(X, Y) CONCATHELP(X,Y)
#define CUMUL CONCAT(cumul,T)
function CUMUL(x) result(y)
!! the cumulative sum of x
TT, intent(in) :: x(:)
!! array of values
TT :: y(size(x))
!! cumulative sum of x
integer :: i, n
n = size(x)
if (n < 1) return
y(1) = x(1)
do i = 2, n
y(i) = y(i-1) + x(i)
end do
end function
#undef T
#undef TT
#undef PASTE
#undef PASTE2
#undef CONCATHELP
#undef CONCAT
#undef CUMUL
Note that when compiling you need to enable the preprocessor (e.g. -cpp
for gfortran):
$ gfortran -cpp -c cumul.f90
$ gfortran cumul.o main.f90
$ ./a.out
1 3 6
1.10000002 3.30000019 6.60000038
1.1000000000000001 3.3000000000000003 6.5999999999999996