Fortran generic functions based on the return kind

馋奶兔 提交于 2020-06-09 04:33:03

问题


I am trying to create a generic function in Fortran based on the value to be returned, that is, depending on if the output of the function is to be assigned to a single precision real or to a double precision real. The code is:

MODULE kk_M

   USE ISO_FORTRAN_ENV

   IMPLICIT NONE

   INTEGER, PARAMETER :: sp = REAL32
   INTEGER, PARAMETER :: dp = REAL64

   INTERFACE use_func
      MODULE PROCEDURE use_sp_func
      MODULE PROCEDURE use_dp_func
   END INTERFACE use_func

   INTERFACE use_sub
      MODULE PROCEDURE use_sp_sub
      MODULE PROCEDURE use_dp_sub
   END INTERFACE use_sub

   CONTAINS

   FUNCTION use_sp_func() RESULT(res)
      REAL(KIND=sp) :: res
      res = 5._sp
   END FUNCTION use_sp_func

   FUNCTION use_dp_func() RESULT(res)
      REAL(KIND=dp) :: res
      res = 5._dp
   END FUNCTION use_dp_func

   SUBROUTINE use_sp_sub(res)
      REAL(KIND=sp), INTENT(OUT) :: res
      res = 5._sp
   END SUBROUTINE use_sp_sub

   SUBROUTINE use_dp_sub(res)
      REAL(KIND=dp), INTENT(OUT) :: res
      res = 5._dp
   END SUBROUTINE use_dp_sub

END MODULE kk_M


PROGRAM kk
   USE kk_M
   IMPLICIT NONE
   REAL(KIND=sp) :: num_sp
   REAL(KIND=dp) :: num_dp

   num_sp = use_func()
   WRITE(*,*) num_sp

   num_dp = use_func()
   WRITE(*,*) num_dp

   CALL use_sub(num_sp)
   WRITE(*,*) num_sp

   CALL use_sub(num_dp)
   WRITE(*,*) num_dp

END PROGRAM kk

With the generic subroutines the code compiles and works, but when I add the generic functions it does not compile. I get the following error message with gfortran:

kk.f90:22:3:

    FUNCTION use_sp_func() RESULT(res)                                                                                                                                             
   1
kk.f90:27:3:

    FUNCTION use_dp_func() RESULT(res)                                                                                                                                             
   2
Error: Ambiguous interfaces in generic interface 'use_func' for ‘use_sp_func’ at (1) and ‘use_dp_func’ at (2)
kk.f90:46:7:

    USE kk_M
       1
Fatal Error: Can't open module file ‘kk_m.mod’ for reading at (1): No existe el archivo o el directorio
compilation terminated.

It looks like the compiler cannot distinguish between both functions based on the value to be returned. Is there some way to achieve this?


回答1:


You cannot distinguish specific functions in a generic interface by their return value. There is no way how the compiler can see what return value type is to be used. A Fortran expression is always evaluated without the surrounding context. Fortran generic disambiguation is based by TKR (type, kind, rank) resolution only using the procedure arguments, not using the return value.

When you have

use_func()

there is no way for the compiler to know which of those two functions should be called. Even when it is used directly in an assignment

 x = use_func()

it is evaluated separately. In general, function calls can appear in various complicated expressions. E.g. use_func(use_func()) + use_func(), which one would be which?

This is the reason why several intrinsic functions have another argument that specifies the return type. For example, the transfer() function has a second argument that specifies which type should be returned. Otherwise the compiler would not be able to find out.




回答2:


Following the advice by Vladimir F, I had a look at the transfer intrisic function and added a mold parameter to my functions to set the return type.

If any input argument to the functions were real they could be used to set the return type as High Performace Mark stated, but since this is not my case I finally used the mold variable.

Now it compiles and work. The code is:

MODULE kk_M

   USE ISO_FORTRAN_ENV

   IMPLICIT NONE

   INTEGER, PARAMETER :: sp = REAL32
   INTEGER, PARAMETER :: dp = REAL64

   INTERFACE use_func
      MODULE PROCEDURE use_sp_func
      MODULE PROCEDURE use_dp_func
   END INTERFACE use_func

   INTERFACE use_sub
      MODULE PROCEDURE use_sp_sub
      MODULE PROCEDURE use_dp_sub
   END INTERFACE use_sub

   CONTAINS

   FUNCTION use_sp_func(mold) RESULT(res)
      REAL(KIND=sp),INTENT(IN) :: mold
      REAL(KIND=sp) :: res
      IF (.FALSE.) res = mold !To avoid compilation warning about unused variable
      res = 5._sp
   END FUNCTION use_sp_func

   FUNCTION use_dp_func(mold) RESULT(res)
      REAL(KIND=dp),INTENT(IN) :: mold
      REAL(KIND=dp) :: res
      IF (.FALSE.) res = mold !To avoid compilation warning about unused variable
      res = 5._dp
   END FUNCTION use_dp_func

   SUBROUTINE use_sp_sub(res)
      REAL(KIND=sp), INTENT(OUT) :: res
      res = 5._sp
   END SUBROUTINE use_sp_sub

   SUBROUTINE use_dp_sub(res)
      REAL(KIND=dp), INTENT(OUT) :: res
      res = 5._dp
   END SUBROUTINE use_dp_sub

END MODULE kk_M


PROGRAM kk
   USE kk_M
   IMPLICIT NONE
   REAL(KIND=sp) :: num_sp
   REAL(KIND=dp) :: num_dp

   num_sp = use_func(1._sp)
   WRITE(*,*) num_sp

   num_dp = use_func(1._dp)
   WRITE(*,*) num_dp

   CALL use_sub(num_sp)
   WRITE(*,*) num_sp

   CALL use_sub(num_dp)
   WRITE(*,*) num_dp

END PROGRAM kk



来源:https://stackoverflow.com/questions/61796019/fortran-generic-functions-based-on-the-return-kind

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!