Reputation: 8140
I want to write a module overloading a swap
routine, which takes an array and two indices and swaps the two elements around.
This routine should work for a wide range of arrays, so I wanted to overload it:
module mod_swap
use iso_fortran_env
implicit none
interface swap
module procedure swap_int64, swap_int32, swap_int16, &
swap_real64, swap_real32
end interface swap
public :: swap
private :: swap_int64, swap_int32, swap_int16, &
swap_real64, swap_real32
contains
#define VAR_TYPE real
#define TYPE_KIND real64
#include "swap.inc"
#undef TYPE_KIND
#define TYPE_KIND real32
#include "swap.inc"
#undef TYPE_KIND
#undef VAR_TYPE
#define VAR_TYPE integer
#define TYPE_KIND int64
#include "swap.inc"
#undef TYPE_KIND
#define TYPE_KIND int32
#include "swap.inc"
#undef TYPE_KIND
#define TYPE_KIND int16
#include "swap.inc"
#undef TYPE_KIND
#undef VAR_TYPE
end module mod_swap
with swap.inc
being:
#define PASTER(x,y) x ## _ ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define SWAP EVALUATOR(swap, TYPE_KIND)
subroutine SWAP(a, i, j)
implicit none
VAR_TYPE(kind=TYPE_KIND), intent(inout) :: a(:)
integer, intent(in) :: i, j
VAR_TYPE(kind=TYPE_KIND) t
t = a(i)
a(i) = a(j)
a(j) = t
end subroutine SWAP
When I run gfortran -o test.o -c -cpp test.F90
it fails, and when I run gfortran -E -cpp test.F90
I find out why: the SWAP
macro has been expanded to swap ## _ ## int16
, not swap_int16
as expected.
However, cpp
directly works:
$ cpp test.F90 > test.f90
$ gfortran -c -o test.o test.f90
After browsing this forum and Google in general, I have deduced that the issue is this:
The preprocessor is run in traditional mode.
And indeed, cpp --traditional
exhibits the same behaviour as gfortran -E -cpp
So here are my questions:
Is there a better way to implement this routine so that I don't have to repeat the same instructions just because the array type has changed. (Note that the variable t
needs to have the same type as a
).
Is there a way to make gfortran
use the non-traditional preprocessor?
If not, how would I do what I want to do with the traditional preprocessor?
Upvotes: 2
Views: 1017
Reputation: 1123
You can implement what you are looking for by using compiler-dependent preprocessor macros. Note that a similar case was already discussed and answered in Concatenating an expanded macro and a word using the Fortran preprocessor. I believe it could be adapted to your case as follows:
#if defined(__GFORTRAN__) || defined(NAGFOR)
#define PASTE(a) a
#define ADD_TRAIL_USCORE(a) PASTE(a)_
#define CAT(a,b) ADD_TRAIL_USCORE(a)b
#else
#define PASTE(a,b) a ## _ ## b
#define CAT(a,b) PASTE(a,b)
#endif
#define SWAP CAT(swap,TYPE_KIND)
Note that
##
, and hence needs to be added to the exception.#define
above, there is no space between swap,
and TYPE_KIND
. //
.Upvotes: 1