[C++-sig] optimizing away calls to the python runtime -- was [detecting if a function is written in python or C++]
François Duranleau
duranlef at iro.umontreal.ca
Wed Jan 18 21:09:51 CET 2006
On Wed, 18 Jan 2006, mathieu lacage wrote:
> hi,
>
> François Duranleau wrote:
>
>> with C++ name patterns. As a matter of fact, we could also use a hack
>> with the __class__ attribute (it seems like the value for all
>> Boost.Python classes is <type 'Boost.Python.class'>. But what about
>> C++ functions? Are we
>
>
> What would such a hack do ? Recognize which classes are exported by
> boost.python and are thus C++ bound classes ? What would you use this for ?
It could be used like this:
def make_callback( obj ) :
if repr( obj.__class__.__class__ ) \
== "<type 'Boost.Python.class'>" :
return obj
else :
return convert_python_object_to_boost_function( obj )
This solves some of the problems with the approach I suggested using
boost::function (uniformity). I don't like it much more than the name
pattern approach though, especially because if the name of the type ever
changes, it breaks down. Also, to deal with C++ functions, we still have
to define some wrapper functors in C++.
Actually, it is not so hard to write some helpers to make this easier
(wrapping functions). I have updated my example with the use of
make_callback as above and I added some helpers. Everything is still at:
http://www-etud.iro.umontreal.ca/~duranlef/python/
All that being said, coming back to the hack, in a case like your callback
framework, I don't think it can be very useful. Your approach has the
advantage of dealing directly with the non-wrapped function/functor, and
the hack (__class__ attribute) is not very useful in selecting and
instantiating the desired callback wrapper (at least, I don't see how
either).
Now coming back to your framework, you said at some point that the process
could be helped with templates for exporting function wrappers. Well, I
think you could use a pattern similar to the helper I wrote in my new
example. Here is how (not tested):
template < typename Function ,
typename Tag >
struct function_wrapper_callback
: Callback1
{
static Function func ;
void operator () ( int a )
{
func( a ) ;
}
} ;
template < typename Function ,
typename Tag >
Function function_wrapper< Function , Tag >::func = Function() ;
template < typename Tag ,
typename Function >
void
export_function_callback( Function f ,
const char* name )
{
typedef function_wrapper_callback< Function , Tab > callback_type ;
// Ensures unicity of callback_type for f
assert( callback_type::func == Function() ) ;
callback_type::func = f ;
class_< callback_type ,
bases< Callback1 > ,
boost::noncopyable >( name ) ;
}
And in the module section, taking your example of function
'real_function', you could export it like this:
// declare the tag ouside of BOOST_PYTHON_MODULE(...)
struct real_function_tag ;
export_function_callback< real_function_tag >( & real_function ,
"real_function_callback" );
This also should work out of the box with stateless functors.
You can do something similar with methods by adding a member 'self' in the
wrapper (pointer to the object), a constructor with the object to bind to
the method as an argument, and calling the method with ->. in operator().
Actually, I think you could even have a single wrapper for both functions
and method using boost::function and boost::bind.
--
François Duranleau
LIGUM, Université de Montréal
"All wealth is created by human beings using their neurons intelligently."
- Robert Anton Wilson, _Prometheus Rising_, 1983
More information about the Cplusplus-sig
mailing list