Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass kind parameter to subprogram

Is it possible in modern versions of Fortran to pass a kind parameter to a subprogram and to use this to 'cast' variables to this kind? As an example, in the following code I am trying to convert an default integer to an 16-bit integer before printing it.

program mwe

! Could use iso_fortran_env definition of int16, but I am stuck with
! old versions of ifort and gfortran.
! use, intrinsic :: iso_fortran_env, only : int16

implicit none

! 16-bit (short) integer kind.
integer, parameter :: int16 = selected_int_kind(15)

call convert_print(123, int16)

contains

  subroutine convert_print(i, ikind)
    implicit none
    integer, intent(in) :: i
    integer, intent(in) :: ikind

    print*, int(i, ikind)

  end subroutine convert_print

end program mwe

With this example code the Intel Fortran compiler complains that

mwe.f(24): error #6238: An integer constant expression is required in this context. [IKIND]
...
mwe.f(24): error #6683: A kind type parameter must be a compile-time constant [IKIND]

and gfortran complains

'kind' argument of 'int' intrinsic at (1) must be a constant

Using print*, int(i, int16) in place of print*, int(i, ikind) would of course work fine in this case. However, if convert_print were defined in a a module which does not define int16 then this would be useless.

Is there a way of passing a kind parameter as a constant to subprograms?

like image 243
Chris Avatar asked Dec 26 '22 15:12

Chris


1 Answers

I have the same problem. I find extremely inconvenient that it is not allowed to pass the kind datatype as an argument to a procedures. In my case, I am writing write a subroutine to just read a matrix from a file and get the object in the data type that I want to. I had to write four different subroutines: ReadMatrix_int8(…), ReadMatrix_int16(…), ReadMatrix_int32(…) and ReadMatrix_int64(…) which are nothing but the same code with one single line different:

integer(kind=xxxx), allocatable, intent(out) :: matrix(:,:)

It would make sense to write only one subroutine and pass xxxx as an argument. If I find any solution I will let you know. But I am afraid that there is no better solution than writing the four subroutines and then writing an interface to create a generic procedure like:

interface ReadMatrix
     module procedure ReadMatrix_int8
     module procedure ReadMatrix_int16
     module procedure ReadMatrix_int32
     module procedure ReadMatrix_int64
end interface
like image 171
Arkog Avatar answered Jan 08 '23 03:01

Arkog