Search code examples
cython

std::back_inserter does not seem to work when applied to reference


I am wanting to wrap std::set_intersection, but I am getting confusing results.

Code to reproduce error:

%%cython -a -+

from libcpp.vector cimport vector
from libcpp.algorithm cimport set_intersection
from libcpp.iterator cimport back_inserter

cdef vector[int] x, y, z

cdef intersection(vector[int]* i1, vector[int]* i2, vector[int]* o):
    set_intersection(i1.begin(), i1.end(), i2.begin(), i2.end(), back_inserter(o[0]))

x = [1, 2, 3]
y = [1, 3, 5]

intersection(&x, &y, &z)
print(z)

What I think intersection should do:

Take three vector[int] pointers and take the intersection of i1 and i2 and apply push_back to o the elements that are shared between i1 and i2.

I get errors on compilation, however.

C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\iterator(41): error C2825: '_Container': must be a class or namespace when followed by '::'
C:\Users\<redacted>\.ipython\cython\_cython_magic_0c03d6fb9770602e2805cbe448ec2c32fdd0e67d.cpp(2279): note: see reference to class template instantiation 'std::back_insert_iterator<std::vector<int,std::allocator<int>> &>' being compiled
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\iterator(41): error C2510: '_Container': left of '::' must be a class/struct/union
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\iterator(41): error C2182: '_Val': illegal use of type 'void'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\iterator(46): error C2825: '_Container': must be a class or namespace when followed by '::'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\iterator(46): error C2510: '_Container': left of '::' must be a class/struct/union
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\iterator(46): error C2182: '_Val': illegal use of type 'void'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.30.30705\include\iterator(64): error C2528: 'container': pointer to reference is illegal

If I modify the function a little bit by defining a vector in-scope, and copying the values it works just fine.

%%cython -a -+

from libcpp.vector cimport vector
from libcpp.algorithm cimport set_intersection
from libcpp.iterator cimport back_inserter

cdef vector[int] x, y, z

cdef intersection(vector[int]* i1, vector[int]* i2, vector[int]* o):
    cdef vector[int] o2
    set_intersection(i1.begin(), i1.end(), i2.begin(), i2.end(), back_inserter(o2))
    o[0] = o2

x = [1, 2, 3]
y = [1, 3, 5]

intersection(&x, &y, &z)
print()
print(z)

results in

[1, 3]

But, obviously I would like the intersection to fill the appropriate container, and avoid the extra copying.


Solution

  • note: see reference to class template instantiation 'std::back_insert_iteratorstd::vector<int,std::allocator<int> &>' being compiled

    Because std::back_insert_iterator's template parameter is deduced to a reference which is wrong.

    https://en.cppreference.com/w/cpp/iterator/back_insert_iterator

    Instantiating it explicitly could solve the problem:
    back_inserter[vector[int]](o[0])