问题
I'm enough of a novice to not know the terminology, so I can't search the Web for the answer to this.
More than once, in programming, I've wanted to do something like this.
A and B are subroutines, c and d are functions. A and B each call a function multiple times inside them.
call A(c(x))
call A(d(x))
call B(c(x))
call B(d(x))
This structure doesn't work. I'm told that Fortran doesn't support aliasing of functions, at least in this context. (Most search results involving "aliasing" refer to aliasing variables rather than functions, which is why I haven't found an answer.)
So what structure can I use to do this without having to write multiple versions of A and B?
回答1:
Not totally sure I understand what you want, but is it something like the following?
Program f
Implicit None
Interface
Integer Function c( x )
Implicit None
Integer, Intent( In ) :: x
End Function c
Integer Function d( x )
Implicit None
Integer, Intent( In ) :: x
End Function d
End Interface
Call a( 3, c )
Call a( 4, d )
Call b( 5, c )
Call b( 6, d )
Contains
Subroutine a( x, func )
Integer, Intent( In ) :: x
Interface
Integer Function func( x )
Implicit None
Integer, Intent( In ) :: x
End Function func
End Interface
Write( *, * ) 'In a. Func = ', func( x )
End Subroutine a
Subroutine b( x, func )
Integer, Intent( In ) :: x
Interface
Integer Function func( x )
Implicit None
Integer, Intent( In ) :: x
End Function func
End Interface
Write( *, * ) 'In b. Func = ', func( x )
End Subroutine b
End Program f
Integer Function c( x )
Implicit None
Integer, Intent( In ) :: x
c = 2 * x
End Function c
Integer Function d( x )
Implicit None
Integer, Intent( In ) :: x
d = 10 * x
End Function d
Wot now? gfortran -std=f95 f.f90
Wot now? ./a.out
In a. Func = 6
In a. Func = 40
In b. Func = 10
In b. Func = 60
Wot now?
An alternative is procedure pointers, but you'll need a f2003 compiler for that and those are not so common yet - the above is fine back to f90 and even earlier than that External will do what you want, but has less error checking capabilities
回答2:
call A(c(x)) looks like evaluate c(x) and pass that to subroutine A, as IanH says in his comment.
If you want to pass a function "C" that takes an argument of type such as X to subroutine A, there are several ways to do that.
As already mentioned, procedure pointers are a new way. While extremely few compilers exist that support all of the Fortran 2003 standard, this portion is widely supported.
Here is an example adapted from Function pointer arrays in Fortran
module ProcsMod
implicit none
contains
function f1 (x)
real :: f1
real, intent (in) :: x
f1 = 2.0 * x
return
end function f1
function f2 (x)
real :: f2
real, intent (in) :: x
f2 = 3.0 * x**2
return
end function f2
subroutine fancy (func, x, answer)
real, intent (in) :: x
real, intent (out) :: answer
interface AFunc
function func (y)
real :: func
real, intent (in) ::y
end function func
end interface AFunc
answer = func (x)
end subroutine fancy
end module ProcsMod
program test_proc_ptr
use ProcsMod
implicit none
interface
function func (z)
real :: func
real, intent (in) :: z
end function func
end interface
procedure (func), pointer :: f_ptr => null ()
real :: answer
f_ptr => f1
call fancy (f_ptr, 2.0, answer)
write (*, *) answer
f_ptr => f2
call fancy (f_ptr, 2.0, answer)
write (*, *) answer
stop
end program test_proc_ptr
The calls "call fancy (f_ptr, 2.0, answer)" look the same, but by changing the function that the function pointer f_ptr points to, a different function is passed to the subroutine fancy.
This compiles with both gfortran (versions 4.4 to 4.7) and ifort.
回答3:
I think M.S.B.'s answer describes what you mean by aliasing of functions; the Fortran terminology is "procedure pointers". As an alternative to this and Ian's answer, you can also use procedure dummy arguments (which are not necessarily pointers). Note that any procedure
declaration is only supported since F2003, but gfortran 4.7 and ifort 13 both support this. It can be done with or without an (abstract) interface block:
module dummy_procedure
implicit none
abstract interface
real function myfunc(x)
real, intent(in) :: x
end function
end interface
contains
subroutine a(func)
! Using the interface block:
procedure(myfunc) :: func
print*, 'a:', func(.5)
end subroutine
subroutine b(func)
! Using the explicit interface of a known procedure:
procedure(f1) :: func
print*, 'b:', func(.5)
end subroutine
real function f1(x)
real, intent(in) :: x
f1 = 2.0 * x
end function
real function f2(x)
real, intent(in) :: x
f2 = 3.0 * x**2
end function
end module
Now you can pass f1
and f2
directly into a
and b
, and the output is as expected:
program main
use dummy_procedure
call a(f1) ! a: 1.0
call a(f2) ! a: 0.75
call b(f1) ! b: 1.0
call b(f2) ! b: 0.75
end program
回答4:
If I understand what you're trying to do:
1) Define your functions in a module.
2) Use the module.
3) Supply the function and the input data to the subroutine as separate arguments.
Here's a code that worked for me:
module iterfuncs
contains
! two example functions:
function approach_golden_ratio(a) result(agr)
agr=1./a+1.
end function approach_golden_ratio
function approach_other_ratio(a) result(aor)
aor=1./(a-1)
end function approach_other_ratio
end module
program use_some_functions
use iterfuncs
real :: final_res
final_res=2.3
! call subroutine with 1st function
call iterate(final_res,approach_golden_ratio)
print *,final_res
final_res=2.3
! call subroutine with 2nd function
call iterate(final_res,approach_other_ratio)
print *,final_res
end program
subroutine iterate(res,func)
use iterfuncs
do n=1,100
res=func(res)
enddo
return
end subroutine
来源:https://stackoverflow.com/questions/13616416/calling-a-subroutine-multiple-times-with-different-function-as-argument-each-tim