1

下面的代码来自这个文件。它在 Linux 上编译正确,但在 OS X 上编译失败。

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

stdsort(intervals.begin(), intervals.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

我得到的错误如下:

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.

问题似乎是其中一种类型。

我有

'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(), intervals.end(), dereference(compare_start_end))

相反,它会出错

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))
                                                       ^

你有什么建议吗?附言。上面在 linux 上编译,但在 macOS 上不编译,所以代码很脆弱。


系统信息

macOS 莫哈韦,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_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)

编译:

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 上弹出。

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

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++

尝试更改 Cython 代码

在 cdef 测试之前添加这些行

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

结果(在 linux 和 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

根据评论结果在 stdsort(...) 末尾添加“排序”(linux和macOS):

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


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

1 回答 1

4

基本问题是 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.end(), __pyx_f_5epic2_3src_8read_bam_compare_start_end);

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

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

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))

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

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

最终结果是 Cython 不再试图告诉 C++ 模板参数应该是什么。


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

cdef extern from "<algorithm>" namespace "std":
    Iter unique[Iter](Iter, Iter, ...)
于 2019-08-21T07:45:30.757 回答