Re: [C++-sig] Returning values to Python in C++ reference arguments

2015-05-26 Thread Holger Joukl

> 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

Re: [C++-sig] Returning values to Python in C++ reference arguments

2015-05-26 Thread Jason Addison
On Mon, May 25, 2015 at 3:39 AM, Trigve Siver via Cplusplus-sig
 wrote:
>
>
>>
>> How can results be returned in function arguments?
>>
>
>
> I don't think that you can return arguments by reference/pointers in python. 
> You could theoretically pass a mutable sequence (list) and push the objects 
> there.
>

You can return results via function arguments from C to Python (see code below).

Why is something similar impossible with Boost Python?

my_module2.c

/*
clang -c -I/usr/include/python2.7 my_module2.c
clang -dynamiclib -o my_module2.so -lpython2.7 my_module2.o
 */

void foo_bar(int *a, double *b) {
*a = 12;
*b = 6.2832;
}


byref2.py

from ctypes import *
my_module2 = CDLL('my_module2.so')

x = c_int(0)
y = c_double(0)

my_module2.foo_bar(byref(x), byref(y))

assert(x.value == 12)
assert(y.value == 6.2832)


> But the common approach is to return tuple.
___
Cplusplus-sig mailing list
[email protected]
https://mail.python.org/mailman/listinfo/cplusplus-sig


Re: [C++-sig] Returning values to Python in C++ reference arguments

2015-05-26 Thread Holger Joukl
Hi,

> Von: Jason Addison
> You can return results via function arguments from C to Python (see
> code below).
>
> Why is something similar impossible with Boost Python?
>
> my_module2.c
> 
> /*
> clang -c -I/usr/include/python2.7 my_module2.c
> clang -dynamiclib -o my_module2.so -lpython2.7 my_module2.o
>  */
>
> void foo_bar(int *a, double *b) {
> *a = 12;
> *b = 6.2832;
> }
> 
>
> byref2.py
> 
> from ctypes import *
> my_module2 = CDLL('my_module2.so')
>

Because you don't create Python built-in int or float objects here:

> x = c_int(0)
> y = c_double(0)

What does type(x) and type(y) give you?

> my_module2.foo_bar(byref(x), byref(y))
>
> assert(x.value == 12)
> assert(y.value == 6.2832)
> 

(unrelated sidenote: it's probably not the best idea to test float/double
equality)

Best regards
Holger

Landesbank Baden-Wuerttemberg
Anstalt des oeffentlichen Rechts
Hauptsitze: Stuttgart, Karlsruhe, Mannheim, Mainz
HRA 12704
Amtsgericht Stuttgart

___
Cplusplus-sig mailing list
[email protected]
https://mail.python.org/mailman/listinfo/cplusplus-sig