无法将std :: sort中的cdef函数用作比较函数 [英] Unable to use cdef function in std::sort as comparison function

查看:81
本文介绍了无法将std :: sort中的cdef函数用作比较函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码来自此文件。它可以在Linux上正确编译,但不能在OS X上编译。



我想对自定义间隔的向量进行排序:

  stdsort(intervals.begin(),interval.end(),compare_start_end)

我的比较函数如下:

  cdef uint32_t compare_start_end(interval lhs,interval rhs ):
if(lhs.start< rhs.start):
return< uint32_t> 1
elif(rhs.start< lhs.start):
return< uint32_t> 0
elif(lhs.end< rhs.end):
return< uint32_t> 1
else:
return< uint32_t> 0

我得到的错误如下:

 在epic2 / src / read_bam.cpp:651包含的文件中:
/ Library / Developer / CommandLineTools / usr / include / c ++ / v1 / algorithm:4117:5 :错误:没有匹配函数调用'__sort'
__sort< _Comp_ref>(__ first,__last,__comp);
^ ~~~~~~~~~~~~~~~
epic2 / src / read_bam.cpp:3305:12:注意:在函数模板特化的实例化'std :: __ 1中::排序<的std :: __ 1 :: __ wrap_iter< __ pyx_t_5epic2_3src_8read_bam_interval *>中无符号整数(__pyx_t_5epic2_3src_8read_bam_interval,__pyx_t_5epic2_3src_8read_bam_interval)GT;
请求这里
标准::分页和LT;的std ::矢量< __ pyx_t_5epic2_3src_8read_bam_interval> :: iterator,uint32_t(__pyx_t_5epic2_3src_8read_bam_interval,__pyx_t_5epic2_3src_8read_bam_interval)>(__ pyx_v_intervals.begin(),__pyx_v_intervals.end_f_start_b)(3,__ pyx_v_intervals.end_2)
^
/ Library / Developer / CommandLineTools / usr / include / c ++ / v1 / algorithm:3914:1:注意:候选函数模板不可行:无法从'unsigned int(*)(__ pyx_t_5epic2_3src_8read_bam_interval ,__pyx_t_5epic2_3src_8read_bam_interval)'为'unsigned int
(&)(__ pyx_t_5epic2_3src_8read_bam_interval,__pyx_t_5epic2_3src_8read_bam_interval)'为第三个参数;用*
__sort(_RandomAccessIterator __first,_RandomAccessIterator __last,_Compare __comp)解引用该参数
^
产生1条警告和1条错误。

问题似乎是其中一种。



我有

 'unsigned int(*)(__ pyx_t_5epic2_3src_8read_bam_interval,__pyx_t_5epic2_3src_8read_bam_interval)'

但我的函数期望

  unsigned int (&)(__ pyx_t_5epic2_3src_8read_bam_interval,__pyx_t_5epic2_3src_8read_bam_interval)

提示是试图取消引用第三个参数,但是

  stdsort(intervals.begin(),interval.end(),dereference(compare_start_end))

相反,它会出错,

 编译epic2 / src / read_bam.pyx,因为它已更改。 
[1/1] Cythonizing epic2 / src / read_bam.pyx

编译Cython文件时出错:
---------------- --------------------------------------------
..
interval = dereference(it).second
Five_ends = intvec()

if drop_duplicates:

stdsort(intervals.begin(),间隔.end(),dereference(compare_start_end))
^

您有什么建议吗?附言上面的代码是在Linux上编译的,而不是在macOS上编译的,因此代码很脆弱。






系统信息



macOS Mojave,10.14.6(18G87)

  gcc --version 
配置为:--prefix = / Library / Developer / CommandLineTools / usr --with-gxx-include-dir = / Library / Developer / CommandLineTools / SDKs / MacOSX10.14.sdk / usr / include / c ++ / 4.2.1
Apple LLVM版本10.0.1(clang-1001.0.46.4)
目标:x86_64-apple-darwin18.7.0
线程模型:posix
InstalledDir:/ Library / Developer / CommandLineTools / usr / bin



最小的可复制示例



 #libic.stdint cimport uint32_t 
从libcpp.algorithm cimport排序为stdsort
从libcpp.vector cimport向量

ctypedef结构间隔:
uint32_t开始
uint32_t结束

ctypedef vector [uint32_t] intvec
ctypedef vector [interval] interval_vector


cdef ui nt32_t compare_start_end(interval lhs,interval rhs):
if(lhs.start< rhs.start):
return< uint32_t> 1
elif(rhs.start< lhs.start):
return< uint32_t> 0
elif(lhs.end< rhs.end):
return< uint32_t> 1
else:
return< uint32_t> 0


cdef测试(interval_vector间隔):
stdsort(intervals.begin(),interval.end(),compare_start_end)

编译方式:

  folder_with_Python_h = / mnt / work / endrebak / software / anaconda / include / python3.7m / 
cython --cplus minimal_example.pyx
gcc -I $ folder_with_Python_h -c minimal_example.cpp -o minimal_example.o -Ofast- Wall -std = c ++ 11

在macOS上弹出相同的错误消息,但在Linux上不弹出。 / p>

我尝试过的其他命令,给出的结果相同:

  g ++ -I /用户/endrebakkenstovner/anaconda3/include/python3.6m/ -stdlib = libc ++ -c minimal_example.cpp -o minimal_example.o -Ofast -Wall 
gcc -I /用户/用户/ endrebakkenstovner / anaconda3 / include / python3 .6m / -c minimal_example.cpp -o minimal_example.o -Ofast -Wall -lc ++



尝试更改Cython代码



在cde之前添加这些行f测试

  cdef来自< algorithm>的外部命名空间 std:
void stdsort(...)

导致linux和macOS)

 编译Cython文件时出错:
------------- -----------------------------------------------
...来自< algorithm>的
cdef extern命名空间 std:
void stdsort(...)


cdef test(interval_vector interval):
stdsort(intervals.begin(),interval.end (),compare_start_end)
^
------------------------------------ ------------------------

minimal_example.pyx:30:11:模棱两可的重载方法

根据注释结果(在linux和macOS上)在stdsort(...)末尾添加 sort: / p>

 编译Cython文件时出错:
------------------ ------------------------------------------
...
else:
return< uint32_t> 0< algorithm>中的cdef extern c $


$ bcdef命名空间 std:
void stdsort(...) sort
^
---------------------- --------------------------------------


解决方案

基本问题是Cython坚持指定模板参数。而不是生成看起来像这样的C代码:

  std :: sort(__ pyx_v_intervals.begin(),__pyx_v_intervals.end(), __pyx_f_5epic2_3src_8read_bam_compare_start_end); 

它会生成

  std :: sort< std :: vector< __ pyx_t_5epic2_3src_8read_bam_interval> :: iterator,uint32_t(__pyx_t_5epic2_3src_8read_bam_interval,__pyx_t_5epic2_3src_8read_bam_interval)>(__ pyx_v_intervals.begin(),__pyx_v_intervals._3_rc_end_f)(_ 3) 

通常在C ++中,最好让C ++找出模板参数。在这种情况下,我认为Cython可能弄乱了函数指针参数。



解决方案是不要告诉Cython您有模板函数。涉及的是自己重新包装功能,而不是使用Cython的libcpp包装器。一种选择是只指定所有类型-类型不必完全匹配 ,但必须足够接近以使Cython认为它可以传递正确的参数:


来自< algorithn>的

  cdef extern名称空间 std:
#代码未经测试,因为这不是我使用的解决方案...
void sort(vector [interval] .iterator,vector [interval] .iterator,
uint32_t(*)(间隔,间隔))

我更喜欢只使用。 .. 。它旨在包装C varargs函数,例如 printf ,您可以在其中传递任何内容,但在这里也可以很好地运行:



<$来自< algorithm>的p $ p> cdef extern名称空间 std:
void sort(...)
#重命名为stdsort do
void stdsort sort(...)

最终结果是Cython停止尝试告诉C ++模板参数应该是什么。



< hr>

std :: unique 有点复杂,因为它具有返回类型。因此,Cython需要知道至少一个模板参数。幸运的是,我很确定只有最后一个参数会引起问题,因此您可以安全地告诉Cython第一个参数是模板:

  cdef extern来自< algorithm>名称空间 std:
Iter unique [Iter](Iter,Iter,...)


The code below is from this file. It compiles correctly on Linux, but fails to compile on OS X.

I want to sort a vector of self-defined intervals:

stdsort(intervals.begin(), intervals.end(), compare_start_end)

My comparison function is the following:

cdef uint32_t compare_start_end(interval lhs, interval rhs):
  if (lhs.start < rhs.start):
    return <uint32_t> 1
  elif (rhs.start < lhs.start):
      return <uint32_t> 0
  elif (lhs.end < rhs.end):
      return <uint32_t> 1
  else:
    return <uint32_t> 0

The error I get is the following:

In file included from epic2/src/read_bam.cpp:651:
/Library/Developer/CommandLineTools/usr/include/c++/v1/algorithm:4117:5: error: no matching function for call to '__sort'
    __sort<_Comp_ref>(__first, __last, __comp);
    ^~~~~~~~~~~~~~~~~
epic2/src/read_bam.cpp:3305:12: note: in instantiation of function template specialization 'std::__1::sort<std::__1::__wrap_iter<__pyx_t_5epic2_3src_8read_bam_interval *>, unsigned int (__pyx_t_5epic2_3src_8read_bam_interval, __pyx_t_5epic2_3src_8read_bam_interval)>'
      requested here
      std::sort<std::vector<__pyx_t_5epic2_3src_8read_bam_interval> ::iterator,uint32_t (__pyx_t_5epic2_3src_8read_bam_interval, __pyx_t_5epic2_3src_8read_bam_interval)>(__pyx_v_intervals.begin(), __pyx_v_intervals.end(), __pyx_f_5epic2_3src_8read_bam_compare_start_end);
           ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/algorithm:3914:1: note: candidate function template not viable: no known conversion from 'unsigned int (*)(__pyx_t_5epic2_3src_8read_bam_interval, __pyx_t_5epic2_3src_8read_bam_interval)' to 'unsigned int
      (&)(__pyx_t_5epic2_3src_8read_bam_interval, __pyx_t_5epic2_3src_8read_bam_interval)' for 3rd argument; dereference the argument with *
__sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
^
1 warning and 1 error generated.

The problem seems to be one of types.

I have

'unsigned int (*)(__pyx_t_5epic2_3src_8read_bam_interval, __pyx_t_5epic2_3src_8read_bam_interval)' 

but my function expects

unsigned int (&)(__pyx_t_5epic2_3src_8read_bam_interval, __pyx_t_5epic2_3src_8read_bam_interval)

The hint is to try to dereference the third argument, but this does not work.

stdsort(intervals.begin(), intervals.end(), dereference(compare_start_end))

Instead, it errors with

Compiling epic2/src/read_bam.pyx because it changed.
[1/1] Cythonizing epic2/src/read_bam.pyx

Error compiling Cython file:
------------------------------------------------------------
...
        intervals = dereference(it).second
        five_ends = intvec()

        if drop_duplicates:

            stdsort(intervals.begin(), intervals.end(), dereference(compare_start_end))
                                                       ^

Do you have any advice? Ps. the above compiles on linux, but not on macOS, so the code is brittle.


System info

macOS Mojave, 10.14.6 (18G87)

gcc --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

Minimal reproducible example

# minimal_example.pyx
from libc.stdint cimport uint32_t
from libcpp.algorithm cimport sort as stdsort
from libcpp.vector cimport vector

ctypedef struct interval:
    uint32_t start
    uint32_t end

ctypedef vector[uint32_t] intvec
ctypedef vector[interval] interval_vector


cdef uint32_t compare_start_end(interval lhs, interval rhs):
  if (lhs.start < rhs.start):
    return <uint32_t> 1
  elif (rhs.start < lhs.start):
      return <uint32_t> 0
  elif (lhs.end < rhs.end):
      return <uint32_t> 1
  else:
    return <uint32_t> 0


cdef test(interval_vector intervals):
    stdsort(intervals.begin(), intervals.end(), compare_start_end)

Compile with:

folder_with_Python_h="/mnt/work/endrebak/software/anaconda/include/python3.7m/"
cython --cplus minimal_example.pyx
gcc -I $folder_with_Python_h  -c minimal_example.cpp -o minimal_example.o -Ofast -Wall -std=c++11

Same error message pops up on macOS, but not linux.

Other commands I have tried, giving the same results:

g++  -I /Users/endrebakkenstovner/anaconda3/include/python3.6m/ -stdlib=libc++  -c minimal_example.cpp -o minimal_example.o -Ofast -Wall
gcc  -I /Users/endrebakkenstovner/anaconda3/include/python3.6m/  -c minimal_example.cpp -o minimal_example.o -Ofast -Wall -lc++

Attempts to change the Cython code

Adding these lines before cdef test

cdef extern from "<algorithm>" namespace "std":
    void stdsort(...)

results in (on both linux and macOS)

Error compiling Cython file:
------------------------------------------------------------
...
cdef extern from "<algorithm>" namespace "std":
    void stdsort(...)


cdef test(interval_vector intervals):
    stdsort(intervals.begin(), intervals.end(), compare_start_end)
          ^
------------------------------------------------------------

minimal_example.pyx:30:11: ambiguous overloaded method

Adding "sort" at the end of stdsort(...) as per the comment results in (both linux and macOS):

Error compiling Cython file:
------------------------------------------------------------
...
  else:
    return <uint32_t> 0


cdef extern from "<algorithm>" namespace "std":
    void stdsort(...) "sort"
                     ^
------------------------------------------------------------

解决方案

The basic problem is that Cython insists on specifying the template arguments. Instead of generating C code that looks like:

std::sort(__pyx_v_intervals.begin(), __pyx_v_intervals.end(), __pyx_f_5epic2_3src_8read_bam_compare_start_end);

it generates

std::sort<std::vector<__pyx_t_5epic2_3src_8read_bam_interval> ::iterator,uint32_t (__pyx_t_5epic2_3src_8read_bam_interval, __pyx_t_5epic2_3src_8read_bam_interval)>(__pyx_v_intervals.begin(), __pyx_v_intervals.end(), __pyx_f_5epic2_3src_8read_bam_compare_start_end);

Generally in C++ it's better to let C++ figure out the template arguments. In this case I think Cython has probably messed up the function pointer argument.

The solution is to not tell Cython that you have a template function. The involves re-wrapping the functions yourself rather than using Cython's libcpp wrappers. One option is to just specify all the types - the types don't have to match exactly but have to be close enough that Cython thinks it can pass the right arguments:

cdef extern from "<algorithn>" namespace "std":
    # code is untested because this isn't the solution I used...
    void sort(vector[interval].iterator, vector[interval].iterator,
              uint32_t (*)(interval, interval))

I prefer just using .... This was designed to wrap C varargs functions like printf where you can pass anything but it works perfectly well here too:

cdef extern from "<algorithm>" namespace "std":
    void sort(...)
    # to rename to stdsort do
    void stdsort "sort"(...)

The end result is that Cython stops trying to tell C++ what the template arguments should be.


std::unique is a little more complicated since it has a return type. Therefore Cython needs to know at least one template argument. Fortunately I'm pretty sure that only the last argument is causing problems, so you can safely tell Cython about the first argument being a template:

cdef extern from "<algorithm>" namespace "std":
    Iter unique[Iter](Iter, Iter, ...)

这篇关于无法将std :: sort中的cdef函数用作比较函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆