Reputation: 6194
I am trying to wrap a handwritten templated C++ array class in Python using Cython. The code does not compile, because the operator()
that should return a reference triggers an error during compilation: Cannot assign to or delete this
. How can I make my code compile?
My .pyx
file is:
# distutils: language = c++
import cython
import numpy as np
cimport numpy as np
cdef extern from "<array>" namespace "std":
cdef cppclass Dim_array_2 "std::array<int, 2>":
Dim_array_2() except+
int& operator[](size_t)
cdef extern from "Array.h":
cdef cppclass Array_2 "Array<double>":
Array_2() except +
void set_dims(const Dim_array_2&) except +
double& operator()(const Dim_array_2&)
def print_index():
cdef Dim_array_2 dims
dims[0] = 3
dims[1] = 5
cdef Array_2 a
a.set_dims(dims)
cdef Dim_array_2 index
counter = 0.
for j in range(dims[1]):
for i in range(dims[0]):
index[0] = i+1
index[1] = j+1
a(index) = counter # This fails.
counter += 1.
index[0] = 2
index[1] = 3
print(a(index))
A simplified version of the corresponding C++ Array.h
is:
#include <array>
#include <vector>
template<typename TF>
class Array
{
public:
Array() {}
void set_dims(const std::array<int,2>& dims)
{
data.resize(dims[0]*dims[1]);
this->dims = dims;
}
TF& data operator()(const std::array<int, 2>& index)
{
return data[ (index[0]-1) + (index[1]-1)*dims[0] ];
}
private:
std::vector<TF> data;
std::array<int,2> dims;
};
The complete error message is:
Error compiling Cython file:
------------------------------------------------------------
...
counter = 0.
for j in range(dims[1]):
for i in range(dims[0]):
index[0] = i+1
index[1] = j+1
a(index) = counter # This fails.
^
------------------------------------------------------------
test.pyx:31:13: Cannot assign to or delete this
Upvotes: 1
Views: 232
Reputation: 30912
I think operator[]
has been specifically special-cased to work, so the fact it works in supposedly similar circumstances doesn't tell you much.
I think in general Cython will struggle to make this syntax work. It doesn't completely understand C++ references, and C++ calls often use temporary variables (to help wrap the C++ exception handling), and these definitely don't work well with references.
You'll probably have to abandon the "nice" array(index) = value
syntax, and write a small C++ wrapper function to help you:
cdef extern from "Array.h":
"""
void setArrayValue(Array<double>& arr, const std::array<int, 2>& idx, double value) {
arr(idx) = value;
}
"""
# ...
(I've used Cython's docstring syntax for including small C/C++ code snippets.)
Within your Cython code you'd then do setArrayValue(a, index, counter)
instead.
Upvotes: 2