使用std::back_inserter处理引用失效,包装std::set_intersection遇编译错误
包装std::set_intersection时的编译错误及优化需求
错误复现代码
%%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)
编译错误信息
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
临时可行但存在额外拷贝的代码
%%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)
运行结果:
[1, 3]
核心诉求
希望直接将交集结果push_back到传入的目标容器指针o指向的容器中,避免临时容器带来的额外拷贝操作。
解决方案
问题根源是back_inserter(o[0])的写法:Cython处理o[0]时,传递给back_inserter的是容器的引用,而std::back_insert_iterator需要的是直接的容器对象(值类型),这导致模板推导错误,生成了不符合标准库要求的std::back_insert_iterator<std::vector<int>&>实例。
有两种修正方式:
方式1:显式获取容器引用
%%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): # 先获取容器的引用,再传入back_inserter cdef vector[int]& o_ref = o[0] set_intersection(i1.begin(), i1.end(), i2.begin(), i2.end(), back_inserter(o_ref)) x = [1, 2, 3] y = [1, 3, 5] intersection(&x, &y, &z) print(z)
方式2:直接解引用指针
%%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)) x = [1, 2, 3] y = [1, 3, 5] intersection(&x, &y, &z) print(z)
两种写法都能让Cython正确推导模板参数,生成标准的std::back_insert_iterator<std::vector<int>>实例,从而直接在目标容器中插入元素,彻底避免额外拷贝。
内容的提问来源于stack exchange,提问作者Todd Sierens
相关产品推荐
相关产品推荐

