Pybind11错误:没有匹配的调用函数

问题描述 投票:0回答:1

我正在尝试为Python构建一个DLL,它使用Qt5库;下面的示例定义了一个函数,并且大多数情况下一切都有效 - 除了我无法使方法 QString::toLocal8Bit 可用于 Python。

我的平台信息:

$ for ic in "$(cmd //c ver)" "uname -s" "python3 --version" "g++ --version"; do echo "$ic:" $(echo "$(${ic})" | head -1); done 2>/dev/null

Microsoft Windows [Version 10.0.19045.4355]:
uname -s: MINGW64_NT-10.0-19045
python3 --version: Python 3.11.9
g++ --version: g++.exe (Rev6, Built by MSYS2 project) 13.2.0

$ python3 -c 'from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR; print("Qt: v", QT_VERSION_STR, "\tPyQt: v", PYQT_VERSION_STR)'
Qt: v 5.15.12   PyQt: v 5.15.10

这里是

QtTestLib.cpp

#include <pybind11/pybind11.h> // pacman -S mingw-w64-x86_64-pybind11

#include <QStringList>

#include <iostream>

QString myStringTesterFunc(const QString &inString, bool specProcess)
{
  QString ret_str  = "Result: ";
  ret_str.append(QString("%1").arg(inString));
  ret_str.append(QString("%1").arg(" - "));
  if (specProcess)
  {
    ret_str.append(QString("%1").arg("Special"));
  }
  else
  {
    ret_str.append(QString("%1").arg("Regular"));
  }
  return ret_str;
}

namespace py = pybind11;

// "The module name (example) is given as the first macro argument (it should not be in quotes)."

PYBIND11_MODULE(QtTestLib, m) {
  m.doc() = "pybind11 example module (myStringTesterFunc)"; // optional module docstring
  m.def("myStringTesterFunc", &myStringTesterFunc, "A function that tests QString");
  py::class_<QString>(m, "QString")
    .def(py::init<const char*>())
    //.def("toLocal8Bit", &QString::toLocal8Bit)
  ;
}

编译:

g++ -g -Wall -Wextra -O -pedantic -shared -std=c++11 -fPIC $(\python3 -m pybind11 --includes) QtTestLib.cpp -o QtTestLib$(python3-config --extension-suffix) -I/mingw64/include/QtCore -I/mingw64/include/python3.11 $(python3-config --ldflags) /mingw64/bin/Qt5Core.dll $(python3-config --libs)

这编译得很好,对我来说生成了一个

QtTestLib.cp311-mingw_x86_64.pyd
文件。

这是

QtTestLib.py

import QtTestLib
print(QtTestLib.myStringTesterFunc)
print(QtTestLib.QString)
qstringret = QtTestLib.myStringTesterFunc(QtTestLib.QString("Hello world"), True)
print(qstringret)
print(qstringret.toLocal8Bit())

当我运行 Python 脚本时,我得到:

$ python3 QtTestLib.py
<built-in method myStringTesterFunc of PyCapsule object at 0x000001fbd1539d70>
<class 'QtTestLib.QString'>
<QtTestLib.QString object at 0x000001fbd15818b0>
Traceback (most recent call last):
  File "C:/msys64/tmp/QtTestLib.py", line 18, in <module>
    print(qstringret.toLocal8Bit())
          ^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'QtTestLib.QString' object has no attribute 'toLocal8Bit'

我们可以看到有一个返回的对象;然而,发布的 .cpp 代码不会“导出”到Local8Bit,因此 Python 看到“对象没有属性”也就不足为奇了。

现在,取消 .cpp 代码中这一行的注释:

    .def("toLocal8Bit", &QString::toLocal8Bit)

并再次尝试用 g++ 重新编译——我得到:

$ g++ -g -Wall -Wextra -O -pedantic -shared -std=c++11 -fPIC $(\python3 -m pybind11 --includes) QtTestLib.cpp -o QtTestLib$(python3-config --extension-suffix) -I/mingw64/include/QtCore -I/mingw64/include/python3.11 $(python3-config --ldflags) /mingw64/bin/Qt5Core.dll $(python3-config --libs)
QtTestLib.cpp: In function 'void pybind11_init_QtTestLib(pybind11::module_&)':
QtTestLib.cpp:54:9: error: no matching function for call to 'pybind11::class_<QString>::def(const char [12], <unresolved overloaded function type>)'
   52 |   py::class_<QString>(m, "QString")
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   53 |     .def(py::init<const char*>())
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   54 |     .def("toLocal8Bit", &QString::toLocal8Bit)
      |     ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from QtTestLib.cpp:21:
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1574:13: note: candidate: 'template<class Func, class ... Extra> pybind11::class_<type_, options>& pybind11::class_<type_, options>::de (const char*, Func&&, const Extra& ...) [with Extra = Func; type_ = QString; options = {}]'
 1574 |     class_ &def(const char *name_, Func &&f, const Extra &...extra) {
      |             ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1574:13: note:   template argument deduction/substitution faileC:
QtTestLib.cpp:54:9: note:   couldn't deduce template parameter 'Func'
   52 |   py::class_<QString>(m, "QString")
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   53 |     .def(py::init<const char*>())
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   54 |     .def("toLocal8Bit", &QString::toLocal8Bit)
      |     ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1599:13: note: candidate: 'template<class T, class ... Extra, typename stC::enable_if<T::op_enable_if_hook, int>::type <anonymous> > pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(const T&, const Extra& ...) [with Extra = T; typename stC::enable_if<T::op_enable_if_hook, int>::type <anonymous> = {Extra ...}; type_ = QString; options = {}]'
 1599 |     class_ &def(const T &op, const Extra &...extra) {
      |             ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1599:13: note:   template argument deduction/substitution faileC:
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1598:95: error: 'op_enable_if_hook' is not a member of 'char [12]'
 1598 |     template <typename T, typename... Extra, detail::enable_if_t<T::op_enable_if_hook, int> = 0>
      |                                                                                               ^
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1611:13: note: candidate: 'template<class ... Args, class ... Extra> pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(const pybind11::detail::initimpl::constructor<Args ...>&, const Extra& ...) [with Args = {Args ...}; Extra = {Extra ...}; type_ = QString; options = {}]'
 1611 |     class_ &def(const detail::initimpl::constructor<Args...> &init, const Extra &...extra) {
      |             ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1611:13: note:   template argument deduction/substitution faileC:
QtTestLib.cpp:54:9: note:   mismatched types 'const pybind11::detail::initimpl::constructor<Args ...>' and 'const char [12]'
   52 |   py::class_<QString>(m, "QString")
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   53 |     .def(py::init<const char*>())
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   54 |     .def("toLocal8Bit", &QString::toLocal8Bit)
      |     ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1618:13: note: candidate: 'template<class ... Args, class ... Extra> pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(const pybind11::detail::initimpl::alias_constructor<Args ...>&, const Extra& ...) [with Args = {Args ...}; Extra = {Extra ...}; type_ = QString; options = {}]'
 1618 |     class_ &def(const detail::initimpl::alias_constructor<Args...> &init, const Extra &...extra) {
      |             ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1618:13: note:   template argument deduction/substitution faileC:
QtTestLib.cpp:54:9: note:   mismatched types 'const pybind11::detail::initimpl::alias_constructor<Args ...>' and 'const char [12]'
   52 |   py::class_<QString>(m, "QString")
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   53 |     .def(py::init<const char*>())
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   54 |     .def("toLocal8Bit", &QString::toLocal8Bit)
      |     ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1625:13: note: candidate: 'template<class ... Args, class ... Extra> pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(pybind11::detail::initimpl::factory<Args ...>&&, const Extra& ...) [with Args = {Args ...}; Extra = {Extra ...}; type_ = QString; options = {}]'
 1625 |     class_ &def(detail::initimpl::factory<Args...> &&init, const Extra &...extra) {
      |             ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1625:13: note:   template argument deduction/substitution faileC:
QtTestLib.cpp:54:9: note:   mismatched types 'pybind11::detail::initimpl::factory<Args ...>' and 'const char [12]'
   52 |   py::class_<QString>(m, "QString")
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   53 |     .def(py::init<const char*>())
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   54 |     .def("toLocal8Bit", &QString::toLocal8Bit)
      |     ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1631:13: note: candidate: 'template<class ... Args, class ... Extra> pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(pybind11::detail::initimpl::pickle_factory<Args ...>&&, const Extra& ...) [with Args = {Args ...}; Extra = {Extra ...}; type_ = QString; options = {}]'
 1631 |     class_ &def(detail::initimpl::pickle_factory<Args...> &&pf, const Extra &...extra) {
      |             ^~~
C:/msys64/mingw64/lib/python3.11/site-packages/pybind11/include/pybind11/pybind11.h:1631:13: note:   template argument deduction/substitution faileC:
QtTestLib.cpp:54:9: note:   mismatched types 'pybind11::detail::initimpl::pickle_factory<Args ...>' and 'const char [12]'
   52 |   py::class_<QString>(m, "QString")
      |   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   53 |     .def(py::init<const char*>())
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   54 |     .def("toLocal8Bit", &QString::toLocal8Bit)
      |     ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

那么,为什么会出现这个错误,我该如何修复它,这样我就可以在 Python 中使用 QString.toLocal8Bit 了?

python-3.x c++11 qt5 pybind11
1个回答
0
投票

是的 - 虽然我无法回答所提出的问题,但经过一番反复试验后,我找到了一个可行的解决方案。

首先,看

error: no matching function for call to 'pybind11::class_<QString>::def(const char [12], <unresolved overloaded function type>)'
,我意识到那里的[12]将“toLocal8Bit”的大小引用为
\0
中的C字符串(加上
.def("toLocal8Bit", &QString::toLocal8Bit)
C字符串终止符)。所以这似乎是调用
QString::toLocal8Bit
的问题......

所以我查看了我的

/mingw64/include/QtCore/qstring.h
,在那里我可以看到这个:

//...
#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
//...
    Q_REQUIRED_RESULT QByteArray toLocal8Bit() const &
    { return toLocal8Bit_helper(isNull() ? nullptr : constData(), size()); }
    Q_REQUIRED_RESULT QByteArray toLocal8Bit() &&
    { return toLocal8Bit_helper(isNull() ? nullptr : constData(), size()); }
#else
//...
    Q_REQUIRED_RESULT QByteArray toLocal8Bit() const;
//...
    static QByteArray toLocal8Bit_helper(const QChar *data, int size);
//...
    Q_REQUIRED_RESULT QByteArray toLocal8Bit() const;
//...

无论如何,即使可能是,它看起来也不像“普通”C++ 方法,这可能会让模板引擎感到困惑。

然后我在同一个标题中看到了这个:

//...
    const ushort *utf16() const;
//...

...所以我尝试了这个而不是 def for

toLocal8Bit()
:

//...
    .def("utf16", &QString::utf16)
//...

实际上编译得很好,但是Python代码中的

print(qstringret.utf16())
打印出82,这不是我期望的字符串。

最后我尝试公开 toStdString - 最后它成功了;所以这是固定代码,

QtTestLib.cpp
:

#include <pybind11/pybind11.h>

#include <QStringList>

#include <iostream>

QString myStringTesterFunc(const QString &inString, bool specProcess)
{
  QString ret_str  = "Result: ";
  ret_str.append(QString("%1").arg(inString));
  ret_str.append(QString("%1").arg(" - "));
  if (specProcess)
  {
    ret_str.append(QString("%1").arg("Special"));
  }
  else
  {
    ret_str.append(QString("%1").arg("Regular"));
  }
  return ret_str;
}

namespace py = pybind11;

// "The module name (example) is given as the first macro argument (it should not be in quotes)."
PYBIND11_MODULE(QtTestLib, m) {
  m.doc() = "pybind11 example module (myStringTesterFunc)"; // optional module docstring
  m.def("myStringTesterFunc", &myStringTesterFunc, "A function that tests QString");
  py::class_<QString>(m, "QString")
    .def(py::init<const char*>())
    .def("toStdString", &QString::toStdString) // passes - and works like a string in Python!
  ;
}

// tester:

int main(__attribute__((unused)) int argc, __attribute__((unused)) char *argv[])
{
  QString test_str  = "->Main tester<-";
  QString out_str = myStringTesterFunc(test_str, true);
  std::wcout << "Got: " << reinterpret_cast<const wchar_t *>(out_str.utf16()) << " " << std::endl;;
}

编译

QtTestLib.cp311-mingw_x86_64.pyd
:

g++ -g -Wall -Wextra -O -pedantic -shared -std=c++11 -fPIC $(\python3 -m pybind11 --includes) QtTestLib.cpp -o QtTestLib$(python3-config --extension-suffix) -I/mingw64/include/QtCore -I/mingw64/include/python3.11 $(python3-config --ldflags) /mingw64/bin/Qt5Core.dll $(python3-config --libs)

Python 脚本

QtTestLib.py
:

import QtTestLib
print(QtTestLib.myStringTesterFunc)
print(QtTestLib.QString)
qstringret = QtTestLib.myStringTesterFunc(QtTestLib.QString("Hello world"), True)
print(qstringret)
print(qstringret.toStdString())

运行Python脚本:

$ python3 QtTestLib.py
<built-in method myStringTesterFunc of PyCapsule object at 0x0000028326a99d70>
<class 'QtTestLib.QString'>
<QtTestLib.QString object at 0x0000028326ae18b0>
Result: Hello world - Special

嗯,那太好了 - 很高兴看到这个工作......

© www.soinside.com 2019 - 2024. All rights reserved.