How to use C++ operator[] in Cython? - c++

I need to wrap a C++ class FooContainer defining the operator[]:
//foo.h:
#include <vector>
using namespace std;
struct Foo
{
Foo()
: value(42) {};
int value;
};
class FooContainer
{
public:
FooContainer() { this->values = vector<Foo> (100) ;}
Foo operator[](int i) {return values[i];}; // <-- the function I need to call
private:
vector<Foo> values;
};
I'm trying to write the corresponding .pyx file but whatever I try I can't figure out how to use Foo::operator
from cython.operator cimport dereference as deref
cdef extern from "foo.h":
cdef cppclass CppFoo "Foo":
pass
cdef extern from "foo.h":
cdef cppclass CppFooContainer "FooContainer":
FooContainer()
Foo operator[](int)
cdef class Foo:
cdef CppFoo * thisptr
cdef class FooContainer:
cdef CppFooContainer* thisptr
def __cinit__(self):
self.thisptr = new CppFooContainer ()
def __dealloc__(self):
if self.thisptr:
del self.thisptr
self.thisptr = <CppFooContainer*> 0
def __getitem__(self, int i):
cdef CppFoo f = deref(self.thisptr)[i] #just one out of many try
I'm probably missing the trivial solution but I always end up with the error: "Cannot convert Python object to 'CppFoo'". Which is the proper way to use the operator[] ?

The usage of operator[] is correct (Cython does not require special syntax for the array indexing operator), but
cdef extern from "foo.h":
cdef cppclass CppFooContainer "FooContainer":
FooContainer()
Foo operator[](int)
should be:
cdef extern from "foo.h":
cdef cppclass CppFooContainer "FooContainer":
CppFooContainer()
CppFoo operator[](int)
since FooContainer and Foo refer to the Python extension class types declared afterwards rather than the C++ class types from "foo.h".

Related

Overload dereference operator in cython

In previous code, I receive an object of PPho and I want to retrieve the Pho object inside the shared pointer. How can I do that? I tried to access the shared_ptr directly, but it's private. I tried to dereference it twice. Then I tried to overload the dereference operator, but I was not successful (the error is also shown below).
C++ code (hpp):
class PPho {
private:
std::shared_ptr <Pho> PhoPtr;
public:
Pho *operator->() const;
PPho(const PPho &Other);
PPho(const std::shared_ptr <Pho> &Other);
PPho(std::nullptr_t);
PPho();
PPho &operator=(const PPho &Other);
PPho &operator=(const std::shared_ptr <Pho> &Other);
operator std::shared_ptr<Pho>() const;
operator std::weak_ptr<Pho>() const;
operator bool() const;
///Free the pointed resource and set the Pointer to nullptr.
void Reset();
class Pho{
Pho();
}
Cython header code I'm trying to use (pxd):
cdef cppclass Pho:
Pho()
Pho(Pho &Other)
cdef cppclass PPho:
PPho() except +
shared_ptr[Pho] PhoPtr
Pho *operator "*operator->()"
Cython code (pyx):
cdef class PyPPho:
cdef PPho* device
def __cinit__(self):
self.device = NULL
cdef assign_device(self, PPho& device_):
self.device = &device_
cdef get_pho(self):
return deref(self.device).get()
Error message:
cdef Get(self):
return deref(self.device).get()
^
------------------------------------------------------------
Ppho.pyx:43:33: Object of type 'PPho' has no attribute 'get'

Alternative to returning template class in extern "C" with MSVC

I have the following class (and some specilization for certain types):
template <typename Type>
class SimpleOptional {
public:
SimpleOptional(Type content) : value_(true), content_(content) {}
// obviously simplified...
private:
bool value_;
Type content_;
};
which is part of a foreign function interface. The function must be declared with extern "C" like this:
extern "C" SimpleOptional<char*> b(char *a) {
return a + 4; // implicitly constructing SimpleOptional<char*>
}
This code works fine with GCC and Clang on macOS and Linux.
However MSVC does not like it and complains that a function with C linkage may not return a C++ class.
So far I came up with this (where MS_O will only be defined for MSVC):
template <typename Type>
class SimpleOptional {
public:
SimpleOptional(Type content) : value_(true), content_(content) {}
using ContentType = Type;
private:
bool value_;
Type content_;
};
#define MS_O(type) struct { bool b; type::ContentType v; }
extern "C" MS_O(SimpleOptional<char*>) b(char *a) {
return a + 4;
}
Although that fixes the return type issue, I still have no implicit construction and MSVC complains about not being able to convert char* to the return type.
Is there any kind of workaround that doesn't cost me C++ implicit construction?

Cythonic way to wrap boost::geometry::Point accessors

What is the correct cythonic way to wrap the following member functions of a boost::geometry::Point? The code snippet comes from here.
/// #brief Get a coordinate
/// #tparam K coordinate to get
/// #return the coordinate
template <std::size_t K>
inline CoordinateType const& get() const
{
#if defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
BOOST_GEOMETRY_ASSERT(m_created == 1);
BOOST_GEOMETRY_ASSERT(m_values_initialized[K] == 1);
#endif
BOOST_STATIC_ASSERT(K < DimensionCount);
return m_values[K];
}
/// #brief Set a coordinate
/// #tparam K coordinate to set
/// #param value value to set
template <std::size_t K>
inline void set(CoordinateType const& value)
{
#if defined(BOOST_GEOMETRY_ENABLE_ACCESS_DEBUGGING)
BOOST_GEOMETRY_ASSERT(m_created == 1);
m_values_initialized[K] = 1;
#endif
BOOST_STATIC_ASSERT(K < DimensionCount);
m_values[K] = value;
}
I first attempted using:
cdef extern from "s57/data/geometries.h" namespace "bg::model":
cdef cppclass _Geo2 "bg::model::point<double, 2, bg::cs::spherical_equatorial<bg::degree>>":
_Geo2()
_Geo2( const _Geo2& other )
const double get[size_t]() except +
void set[size_t](double) except +
but then I don't know where to go since something like this:
property x:
def __set__(self, double value):
deref(self._p).set[0](value)
gives me this failure:
Error compiling Cython file:
------------------------------------------------------------
...
property x:
def __set__(self, double value):
deref(self._p).set[0](value)
^
------------------------------------------------------------
c:\XXXX\x.pyx:24:31: not parsable as a type
My current working solution has been to create some helper functions like:
double get_geo2_x( geo2& pnt );
double get_geo2_y( geo2& pnt );
void set_geo2_x( geo2& pnt, double value );
void set_geo2_y( geo2& pnt, double value );
Does somebody have in mind a more elegant solution?
You're running into problems with Cython's handling of non-type template parameters. You can manually specify function names using strings, which are inserted directly into the generated C code (see http://docs.cython.org/src/userguide/external_C_code.html#resolving-naming-conflicts-c-name-specifications)
As a very simple example
// example.hpp
#include <iostream>
class C {
template <int K>
void set(double value) {
std::cout << K << ": " << value << std::endl;
}
And the Cython code
cdef extern from "example.hpp":
cdef cppclass C:
void set0 "set<0>"(double) except +
void set1 "set<1>"(double) except +
def do_set():
# very simple illustrative example
cdef C c
c.set0(1.0)
c.set1(1.5)
}
Whenever Cython sees set0 called on a C it substitutes set<0>, calling the template function directly. You can then use properties, as you were trying to do.
This probably isn't significantly better than creating helper functions, but it might be a little easier.

boost-python: How do I provide a custom constructor wrapper function?

I'm using boost-python to create python bindings for a C++ class named CppClass. When necessary, I can route calls to "normal" member functions through little wrapper functions that preprocess the arguments (e.g. extract C++ types from the python args), like so:
class CppClass
{
public:
CppClass(SpecialParameters p);
void doSomething(int x, float y);
};
using namespace boost::python; // For extract, tuple, init, class_, etc.
class WrapperFuncs
{
public:
static void doSomething(CppClass & c, tuple t)
{
// Special extraction: Convert python arg ( a tuple) into C++ args.
int x = extract<int>(t.attr("__getitem__")(0));
float y = extract<float>(t.attr("__getitem__")(1));
c.doSomething(x,y);
}
};
class_<CppClass, boost::shared_ptr<CppClass> >
("CppClass", init<SpecialParameters>())
.def("doSomething", &WrapperFuncs::doSomething, (arg("t")))
But how do I do the same for the CppClass constructor?
Use no_init followed by a .def for __init__ using boost::python::make_constructor().
class WrapperFuncs
{
public:
static boost::shared_ptr<CppClass> initWrapper( object const & p )
{
SpecialParameters sp = ... // do complicated extraction here.
return boost::shared_ptr<CppClass>( new CppClass(sp) );
}
static void doSomething(CppClass & c, tuple t) { /*...*/ }
};
class_<CppClass, boost::shared_ptr<CppClass> >
("CppClass", no_init)
.def("__init__", make_constructor(&WrapperFuncs::initWrapper))
.def("doSomething", &WrapperFuncs::doSomething, (arg("t")))
This section of the python wiki explains how to do this, but it didn't quite work for me because it didn't mention no_init. In my case, no_init was required.

how to call the particular constructor of boost::variant

I have a problem of calling the constructors in boost::variant.
Suppose I have two classes "abc" and "asd" and I have an object declaration something like-
class abc
{
int var;
float var2;
public: abc(int a)
{
var = a;
}
public: abc(inta, float b)
:var(a), var2(b)
{}
};
class asd
{
int var;
public: asd(int a)
{
var = a;
}
};
typedef boost::variant<abc,asd> def;
int main()
{
def my_object;
}
my problem is how do I call the constructor of the object my_object?
From the manual (you must have missed it):
a variant can be constructed directly from any value convertible to
one of its bounded types
And:
Similarly, a variant can be assigned any value convertible to one of
its bounded types
So:
def my_object = asd(3); // or `def my_object(asd(3));`
my_object = abc(4);
A variant is not some multiply-derived custom type, and has its own constructors defined instead. The idiomatic way is to just assign one of the variant types:
typedef boost::variant<abc,asd> def;
int main()
{
def my_object = abc(1);
my_object = abc(1, .4);
}
If you wanted to actually use constructor without without copy-initialization (allthough most compilers will elide the copy) you can write:
def my_object(abc(1,.4));