[C++-sig] Re: Exposing C++ objects to Python at runtime

Raoul Gough RaoulGough at yahoo.co.uk
Wed Nov 26 19:50:30 CET 2003


Daniel Wallin <dalwan01 at student.umu.se> writes:

> Raoul Gough wrote:
>> David Abrahams <dave at boost-consulting.com> writes:
>>
>>>Raoul Gough <RaoulGough at yahoo.co.uk> writes:
>>>
[snip]
>> The only difficulty I've thought of would be handling return values.
>> For instance, somewhere you have to have a conversion from the C++
>> return type to a PyObject * (for the Python engine) or the
>> corresponding type for different engines. Maybe a double-dispatch
>> would handle this, meaning a certain amount of scripting language
>> dependant code in the function descriptor base class?
>
> I thought it would just work like:
>
>    PyObject* python_function_wrapper()
>    {
>        function& fn = /* something */;
>
>        const type_info* args = fn.arg_types();
>
>        void** storage_table = /* something */;
>
>        for (int i = 0; i < fn.arity(); ++i)
>        {
>            void* storage = allocate_storage_for_converter(args[i]);
>            perform_conversion(args[i], i, storage, py_args);

So perform_conversion knows (a) what the scripting engine argument
type is and (b) what the required C++ argument type is. For example,
you have a C++ function:

void do_something (some_udt);

and we need code somewhere to create a some_udt object from a PyObject
*, from a lua_State * or whatever. I guess that means the function
descriptor can't be truly universal, since it is supposed to be the
only place that has compile-time knowledge of the C++ types
involved. e.g.

function<...>::convert_argument0 (PyObject *src, void *dst) {
  // create an arg_vector<0> type from PyObject at dst
}

function<...>::convert_argument0 (lua_State *src, void *dst) {
  // create an arg_vector<0> object from lua_State at dst
}

etc.

>            storage_table[i] = storage;
>        }
>
>        void* result_storage = allocate_storage_for_converter(
>            fn.result_type()
>        );
>
>        fn.invoke(storage_table, result_storage);
>
>        return perform_result_conversion(
>            fn.result_type()
>          , result_storage
>        );

If I'm right about the parameter conversions, then the same would
apply here for the return value conversion.

>    }
>
> and function::invoke, simplified, would just do..
>
>    void function::invoke(void* const* args_storage, void* result_storage)
>    {
>        new (result_storage) ResultType(
>            m_fn(
>                static_cast<A0*>(args_storage[0])
>              , static_cast<A1*>(args_storage[1])
>              , etc..
>            )
>        );
>    }
>
> I guess you'd also need a virtual tail call that can destroy the
> result..
>
> Of course, the converter lookup would be done at init time and stored.

But where does the C++ code for the converter (with compile-time
knowledge of the C++ types) come from?

-- 
Raoul Gough.
export LESS='-X'





More information about the Cplusplus-sig mailing list