2016-09-22 86 views
6

我試圖通過一個通用的程序作爲實際參數傳遞給函數:傳遞一個通用的程序,一個函數作爲實際參數

module mymod 
implicit none 

interface func 
    module procedure :: func1 
    module procedure :: func2 
endinterface func 

contains 

real function func1(x) 
    real,intent(in) :: x 
    func1 = 2*x 
endfunction func1 

real function func2(x,y) 
    real,intent(in) :: x 
    real,intent(in) :: y 
    func2 = 2*x + 3*y 
endfunction func2 

real function func3(func,x,y) 
    interface 
    real function func(x,y) 
     real,intent(in) :: x 
     real,intent(in) :: y 
    endfunction func 
    endinterface 
    real,intent(in) :: x 
    real,intent(in) :: y 
    func3 = func(x,y) 
endfunction func3 

endmodule mymod 

program myprogram 
use mymod 
implicit none 
write(*,*)func3(func,2.,3.) 
endprogram myprogram 

gfortran 6.2.0注意到,我不能做到這一點:

test.f90:43:16: 

write(*,*)func3(func,2.,3.) 
       1 
Error: GENERIC procedure ‘func’ is not allowed as an actual argument at (1) 

同樣,ifort 17:

test.f90(39): error #8164: A generic interface name shall not be used as an actual argument. [FUNC] 
write(*,*)func3(func,2.,3.) 
----------------^ 
test.f90(39): error #6637: When a dummy argument is a function, the corresponding actual argument must also be a function. [FUNC] 
write(*,*)func3(func,2.,3.) 
----------------^ 
compilation aborted for test.f90 (code 1) 

我通過對基因的2008標準部分閱讀ric接口,我找不到這樣的限制。我也想不出爲什麼編譯器不能在編譯時解析通用接口的原因。我的直覺告訴我這應該是可行的,但我可能沒有正確的方法。你知道符合標準的方法嗎?

回答

5

不,這是不允許的。實際上,你甚至不能傳遞通用的INTRINSIC函數作爲虛擬參數。

符合標準的方法是直接使用正確的特定功能。使用INTRINSIC函數時,有時必須編寫適當類型的包裝,當具體沒有標準名稱時。

例如:

call integrate(derf,0.,1.) 

    contains 
    function derf(x) 
     real(dbl) :: derf 
     real(dbl), intent(in) :: x 
     derf = erf(x) 
    end function 
    end 

是必要的,如果你想通過雙精度實(或任何其他)的erf()版本,因爲沒有可用的特定功能。

+1

始終清晰,重點突出,謝謝。 – milancurcic

+6

我會評論說,在Fortran 2015中使用特定函數將變爲非標準。在那一點上,將無法將內部函數作爲過程參數傳遞,並且必須使用包裝器方法來保持符合標準。 (我還注意到,自Fortran 95以來,沒有添加新的特定內部函數名稱。) –

1

Fortran標準不允許將通用過程作爲參數傳遞。爲了傳遞內部函數/子程序,必須使用用戶定義的包裝程序。

module mymod 

    ! Explicit typing only 
    implicit none 

    ! Declare procedure interface 
    interface 
     function my_func(x, y) result (return_value) 
     real, intent(in) :: x, y 
     real    :: return_value 
     end function my_func 
    end interface 

contains 

    function func1(x) result (return_value) 
     real,intent(in) :: x 
     real   :: return_value 

     return_value = 2*x 

    end function func1 

    function func2(x, y) result (return_value) 
     real, intent(in) :: x, y 
     real    :: return_value 

     return_value = 2*x + 3*y 

    end function func2 

    function func3(user_defined_func, x, y) result (return_value) 
     procedure(my_func) :: user_defined_func 
     real, intent(in) :: x, y 
     real    :: return_value 

     return_value = user_defined_func(x,y) 

    end function func3 

end module mymod 

program main 

    use ISO_Fortran_env, only: & 
     stdout => OUTPUT_UNIT, & 
     compiler_version, & 
     compiler_options 

    use mymod 

    ! Explicit typing only 
    implicit none 

    write (stdout, *) func3(func2, 2.0, 3.0) 
    write (stdout, *) func3(foo, 2.0, 3.0) 
    write (stdout, *) func3(my_atan2, 2.0, 3.0) 

    print '(/4a/)', & 
    ' This file was compiled using ', compiler_version(), & 
    ' using the options ', compiler_options() 

contains 

    ! A user defined function 
    function foo(x, y) result (return_value) 
     real, intent(in) :: x, y 
     real    :: return_value 

     return_value = 42 

    end function foo 

    ! A wrapper function to invoke the intrinsic atan2 
    function my_atan2(x, y) result (return_value) 
     real, intent(in) :: x, y 
     real    :: return_value 

     return_value = atan2(x,y) 

    end function my_atan2 

end program main 

產生

gfortran -std=f2008ts -o main.exe mymod.f90 main.f90 
./main.exe 
    13.0000000  
    42.0000000  
    0.588002622  

This file was compiled using GCC version 6.1.1 20160802 using the options -mtune=generic -march=x86-64 -std=f2008ts