How to use inteface blocks to pass a function to a subroutine?

前端 未结 3 628
旧巷少年郎
旧巷少年郎 2021-01-24 06:24

I understand the interface command can be used to pass a a function into a subroutine. So for example in the main program I\'d define some function and then pass it to some subr

相关标签:
3条回答
  • 2021-01-24 07:06

    The most elegant way I know of right now is to put your functions into a module so that you don't have to do construct interface but simply use 'external'. Here is a example to do that.

    It covers different situations using subroutine or function as arguments for subroutine or function.

    Notice if you want to pass array as argument without receiving null arraies, here is a tip to do that.

    Module part:

    module func_arg_test
    !I used ifort to compile but other compilers should also be fine.
    !Written by Kee
    !Feb 20, 2017
    contains
    
    !-------------------------
    real function func_func(f, arg)
    !========================================
    !This shows how to pass number as argument
    !========================================
    implicit none
    real, external::f !Use external to indicate the f is a name of a function
    real::arg
    
    func_func=f(arg)
    end function func_func
    
    real function func_sub(subr, arg)
    !========================================
    !This shows how to pass subroutine as arg to function
    !========================================
    implicit none
    external::subr !Use external to indicate subr is a subroutine
    real::arg
    
    call sub(arg)
    func_sub = arg
    end function func_sub
    
    
    subroutine sub_func(f,arg)
    !========================================
    !This shows how to pass function as argument
    !in subroutine 
    !========================================
    real::arg
    real,external::f
    arg = f(arg)
    end subroutine sub_func
    
    subroutine sub_sub(subr,arg)
    !========================================
    !This shows how to pass subroutine as argument
    !in subroutine 
    !========================================
    real::arg
    external::subr
    call subr(arg)
    end subroutine sub_sub
    
    
    
    
    real function funcmat(f, mat)
    !========================================
    !This shows how to pass matrix as argument
    !========================================
    implicit none
    real, external::f
    real,dimension(:)::mat!Here memory for mat is already allocated when mat is
    !passed in, so don't need specific size
    integer::sizeinfo
    sizeinfo = size(mat)
    funcmat = f(mat,sizeinfo)
    end function funcmat
    !--------------------------
    
    real function f1(arg)
    !This test function double the number arg
    implicit none
    real::arg
    f1 = arg*2
    return
    end function f1
    
    real function f2(arg)
    !This test function square the number arg
    implicit none
    real::arg
    f2 = arg*arg
    return
    end function f2
    
    real function fmat(mat,sizeinfo)
    !This test function sum up all elements in the mat
    implicit none
    integer::sizeinfo!This is the method I come up with to get around the
    !restriction.
    real,dimension(sizeinfo)::mat!This mat cannot be undetermined, otherwise it
    !won't recevie mat correctly. I don't know why yet.
    fmat = sum(mat)
    end function fmat
    
    subroutine sub(arg)
    real::arg
    arg = arg*3
    end subroutine sub
    end module
    

    Main program:

    program main
    use func_arg_test
    implicit none
    real::a = 5d0
    real::output
    real, dimension(:),allocatable::mat
    
    write(*,*) 'value of a=',a
    output = func_func(f1,a)
    write(*,*) 'a is  doubled'
    write(*,*) output
    output = func_func(f2,a)
    write(*,*) 'a is squared'
    write(*,*) output
    output = func_sub(sub,a)
    write(*,*) 'a is tripled and overwritten'
    write(*,*) output
    call sub_func(f2,a)
    write(*,*) 'a is squared and overwritten'
    write(*,*) a
    call sub_sub(sub,a)
    write(*,*) 'a is tripled and overwritten'
    write(*,*) a
    
    allocate(mat(3))
    mat = (/1d0,10d0,1d0/)!The allocatable arrray has to have a determined shape before
    !pass as arguemnt
    write(*,*) '1D matrix:',mat
    write(*,*) 'Summation of the matrix:'
    output = funcmat(fmat,mat)!elements of mat are summed
    write(*,*) output
    
    end program
    

    And the result is:

    value of a=   5.000000    
     a is  doubled
       10.00000    
     a is squared
       25.00000    
     a is tripled and overwritten
       15.00000    
     a is squared and overwritten
       225.0000    
     a is tripled and overwritten
       675.0000    
     1D matrix:   1.000000       10.00000       1.000000    
     Summation of the matrix:
       12.00000    
    
     
    
    0 讨论(0)
  • 2021-01-24 07:13

    A simple way to do this is to go old school and just leave the function external:

     program main
     real f,z
     external f
     call subr(f,z)
     write(*,*)z
     end
    
     real function f(x)
     real x
     f=x**2
     end
    

    ! below possibly in a precompiled library:

     subroutine subr(f,y)
     real f,y
     y=f(2.)
     end
    

    out: 4

    Of course with this approach you can not use advanced language features that require an explicit interface. **

    On the other hand if you are interfacing with standard libraries that need function arguments this is I think the only way.

    ** per MSB's comment you can handle that issue with an interface block in the subroutine, for example if we want to pass a function that returns an array:

     function f(x)
     real x,f(2)
     f(1)=x
     f(2)=x**2
     end
    

    as in the first example f is an external function, and the sub can be in a precompiled library:

     subroutine subr(g,y)
     interface
     function g(x)
     real x,g(2)
     end function
     end interface
     real y,z(2)
     z=g(2.)
     y=z(1)+z(2)
     end
    

    out: 6

    As noted, this is only strictly necessary if relying on language features that need the interface.

    0 讨论(0)
  • 2021-01-24 07:20

    Module:

    module fmod
        interface
           function f_interf(x,y)
           real, intent(in) :: x, y
           real :: f_interf
           end function
        end interface
    
    contains 
        function f_sum(x,y)
        real, intent(in) :: x, y
        real f_sum
    
        f_sum = x + y
    
        end function
    
        function f_subst(x,y)
        real, intent(in) :: x, y
        real f_subst
    
        f_subst = x - y
    
        end function
    
        subroutine subr(limit1, limit2, func, ans)
        real limit1, limit2
        procedure(f_interf) func
        real ans
    
        ans = func(limit1, limit2)
        end subroutine
    end module
    

    main program:

    program pass_func
    use fmod
    Implicit None
    real ans, limit1, limit2
    limit1 = 1.0
    limit2 = 2.0
    call subr( limit1, limit2, f_subst, ans)
    write(*,*) ans
    call subr( limit1, limit2, f_sum, ans)
    write(*,*) ans
    end program pass_func
    

    and output:

      -1.000000
       3.000000
    
    0 讨论(0)
提交回复
热议问题