Go Back   Rhinocerus > Newsgroup > Newsgroup comp.lang.* 1 > Newsgroup comp.lang.fortran

Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old 08-14-2012, 10:35 PM
mlohry@gmail.com
Guest
 
Posts: n/a
Default binding arguments to procedure pointers

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!
Reply With Quote
Alt Today
Advertising
 
and become member of Rhinocerus
Standard Sponsored Links

  #2 (permalink)  
Old 08-15-2012, 02:46 AM
Ian Harvey
Guest
 
Posts: n/a
Default Re: binding arguments to procedure pointers

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 the
programmer.

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)


Reply With Quote
 
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off




All times are GMT. The time now is 01:10 AM.


Copyright ©2009

LinkBacks Enabled by vBSEO 3.3.0 RC2 © 2009, Crawlability, Inc.