|
|||
|
I'd like to pass a procedure pointer as an argument to some other function,but with the arguments to that procedure bound to the pointer. (boost::bind does this in C++: http://www.boost.org/doc/libs/1_50_0...with_functions) i.e., I have some function:
function add(a,b) real ::a,b,add add = a+b end function and I can pass a pointer like so: procedure(real),pointer :: addptr addptr => add call funcptrcall(add,3.0,4.0) [...] subroutine funcptrcall(funcptr,arg1,arg2) procedure(real),pointer :: funcptr write(*,*) funcptr(arg1,arg2) !outputs 7 end subroutine But what I'd like to do is associate that function pointer with specific arguments prior to the call, so "funcptrcall" doesn't need to know how many arguments and what types the function requires, and that subroutine could be subroutine funcptrcall_withargs(funcptr) procedure(real),pointer :: funcptr write(*,*) funcptr() !want this to output 7 end subroutine But there needs to be some glue to bind 3.0 and 4.0 to be the arguments to that function pointer prior to the call. Is there any simple method to do this a la boost::bind? Thanks! |
|
|
||||
|
||||
|
|
|
|||
|
On 2012-08-15 8:35 AM, mlohry@gmail.com wrote:
> I'd like to pass a procedure pointer as an argument to some other function, but with the arguments to that procedure bound to the pointer. (boost::bind does this in C++: http://www.boost.org/doc/libs/1_50_0...with_functions) boost::bind can take advantage of the template facilities of C++ to take much of the necessary generic "glue" code out of the hands of the programmer. Fortran does not have such a facility (supported directly by the language) so additional work needs to be done by theprogrammer. One possible approach - use a abstract type to encapsulate a "functor". You need to be able to modify the called procedure so that it can take an object of such type. Illustrating through head compiled source code snippets, apologies for syntax errors... ! Type that encapsulates a call to a function has a REAL result. TYPE, ASBTRACT :: RealFunctionCall CONTAINS ! This binding is supposed to be the equivalent of operator () ! in C++, but fortran doesn't have the concept of a function ! operator. PROCEDURE(rfc_Eval), DEFERRED, PUBLIC :: Eval END TYPE RealFunctionCall ABSTRACT INTERFACE FUNCTION rfc_Eval(obj) IMPORT :: RealFunctionCall IMPLICIT NONE CLASS(RealFunctionCall), INTENT(IN) :: obj REAL :: rfc_Eval END FUNCTION rfc_Eval END INTERFACE ! Type that encapsulates a call to a function that returns a REAL ! and takes two arguments (specifically here has the interface of ! add (so explicit interface for add needs to be in scope here) ! - if the interface matching is problematic then you could ! make the interface of the procedure pointer implicit). TYPE, EXTENDS(RealFunctionCall) :: TwoArgFunctionCall REAL :: arg_1 REAL :: arg_2 PROCEDURE(add), NOPASS, POINTER :: fun CONTAINS PROCEDURE :: Eval => ta_Eval END TYPE TwoArgFunctionCall FUNCTION ta_Eval(obj) CLASS(TwoArgFunctionCall), INTENT(IN) :: obj REAL :: ta_Eval !**** ! If your functor was always going to be calling add, then you ! could drop the procedure pointer component and hardwire this. ta_Eval = obj%fun(obj%arg_1, obj%arg_2) END FUNCTION ta_Eval ! Procedure that needs to make the call now takes a polymoprhic ! argument object of the abstract type. SUBROUTINE funcptrcall(functor) CLASS(RealFunctionCall), INTENT(IN) :: functor .... thing = functor%Eval() .... END SUBROUTINE funcptrcall ! Example use - pass object of concrete type that has both ! its internal function pointer and arguments set appropriately. .... TYPE(TwoArgFunctionCall) :: functor functor = TwoArgFunctionCall(3.0, 4.0, add) CALL funcptrcall(functor) .... There is a considerable amount of source overhead for a single use - but in an ideal world you would have multiple use cases and the source overhead would be somewhat amortised. Unfortunately conventions on the interface for these sorts of helper libraries are yet to emerge in the language - really the module that defines a functor that returns a REAL needs to be written once, ever, but watch as we all go out there and write our own incompatible variants... Alternative approaches include binding the arguments via module variables and then having the procedure pointer reference a module procedure that knows to reference those module variables. But this is clunky, has issues with recursion, is difficult to re-use, won't impress your significant other, etc. MODULE some_unique_name IMPLICIT NONE REAL :: arg_1 REAL :: arg_2 CONTAINS FUNCTION mod_fun() USE module_that_has_the_interface_for_add REAL :: mod_fun mod_fun = add(arg_1, arg_2) END FUNCTION mod_fun END MODULE some_unique_name ! funcptrcall could then look like... ABSTRACT INTERFACE FUNCTION real_nonary() IMPLICIT NONE REAL :: real_nonary END FUNCTION real_nonary END INTERFACE SUBROUTINE funcptrcall(functor) PROCEDURE(real_nonary) :: functor .... thing = functor() .... END SUBROUTINE funcptrcall ! Example of use USE some_unique_name arg_1 = 3.0 arg_2 = 4.0 CALL funcptrcall(mod_fun) |
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|