> Von: Jason Addison
>
> How can results be returned in function arguments?
>
> I've include my example C++ extension and Python code below.
>
> I've tried, what I think, are some obvious approaches (Python objects,
> ctypes), though none have worked.
>
> It seems like this should be doable.
As already mentioned, you can use helper functions and return tuples.
Or you could expose custom "ref-object" classes to Python, s.th. along the
lines of:
// ref_object.hpp
#if !defined REF_OBJECT
#define REF_OBJECT
#include
#include
namespace bp = boost::python;
namespace refob {
// Basic RefObject
template
struct RefObject {
public:
T t;
RefObject();
// callable operator
T operator()();
// conversion functions: implicit castability
operator T&() { return t; }
};
// RefObject for handling C-style arrays
// This provides an operator() that allows access to
// a list of values.
// NOTE: If numElements > the actual stored number of elements then
// THIS WILL CRASH! It is essential to correctly apply set_num() after
// this has been used as a function argument, in some thin wrappers
// There is only some very rudimentary safety in that _numElements is
// initialized to 0
// I really don't see a better way to make this safer
template
struct RefObject {
T const * t;
RefObject();
// callable operator
bp::list operator()(unsigned int numElements=0);
// conversion functions: implicit castability
operator T const *&() { return t; }
void set_num(unsigned int const & numElements);
private:
unsigned int _numElements;
};
// RefObject specialization for void*
template<>
struct RefObject {
void* t;
RefObject();
// callable operator
void* operator()();
};
// RefObject specialization for void const* (where we cast away const for
the
// operator() call result to make boost work automagically
template<>
struct RefObject {
void const * t;
RefObject();
// callable operator
void* operator()();
};
// RefObject specialization for char const* which boost.python will
automatically
// handle as a python string (necessary to distingish from the C-style
array
// handling RefObject, see above
template<>
struct RefObject {
char const * t;
RefObject();
// callable operator
char const* operator()();
};
// Is inlining the way to go to avoid multiply defined symbols here?
// Note: Remember that
// * a specialization is not a template but a concrete (member function in
// this case)
// * as ref_object.hpp are
//#included from every module there will be multiple definitions (one
//in each compilation unit)
// ==> linker chokes
// Using inline this can be avoided
// See
// http://msdn.microsoft.com/en-us/magazine/cc163769.aspx
// http://www.parashift.com/c++-faq-lite/inline-functions.html
// for background
template
RefObject::RefObject(): t() {
//std::cout << "RefObject<" << typeid(T).name() << ">::RefObject()" <<
std::endl;
}
template
RefObject::RefObject(): t(), _numElements(0) {
//std::cout << "RefObject<" << typeid(T).name() << " const
*>::RefObject()" << std::endl;
}
inline RefObject::RefObject(): t() {
//std::cout << "RefObject::RefObject()" << std::endl;
}
inline RefObject::RefObject(): t() {
//std::cout << "RefObject::RefObject()" << std::endl;
}
inline RefObject::RefObject(): t() {
//std::cout << "RefObject::RefObject()" << std::endl;
}
template
T RefObject::operator()()
{
// Do we need to care about pointer data issues here?
return t;
}
template
bp::list RefObject::operator()(unsigned int numElements)
{
bp::list list_object;
unsigned int maxElements = std::min(numElements, _numElements);
for (unsigned int i=0; i < maxElements; i++) {
bp::object item(*t);
list_object.append(item);
}
return list_object;
}
inline void* RefObject::operator()()
{
void* non_const_ptr = const_cast(t);
//std::cout << "returning non-const void* t" << std::endl;
return non_const_ptr;
}
inline void* RefObject::operator()()
{
return t;
}
inline char const* RefObject::operator()()
{
return t;
}
template
void RefObject::set_num(unsigned int const & numElements)
{
_numElements = numElements;
}
} // namespace refob
#endif // #if !defined REF_OBJECT
And you might expose those to Python:
// ref_object.cpp
#include
#include "ref_object.hpp"
namespace bp = boost::python;
namespace refob
{
// dummy function, expose this to force creation of void* converters in
boost registry
void* void_ptr_from_void_ptr(void* void_ptr) {
return void_ptr;
}
void export_reference_type_classes()
{
// // dummy function registration to force creation of void* converters
// // (not necessary if there is an exposed function returning void*)
// bp::def("void_ptr_from_void_ptr", &void_ptr_from_void_ptr,
// bp::return_value_policy());
// const-pointer types
// 1. char
// 1.1: const char*
b