Skip to content

Rvalue reference parameters work in constructors, but not in other functions #1694

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Boris-Rasin opened this issue Feb 15, 2019 · 5 comments · Fixed by #2048
Closed

Rvalue reference parameters work in constructors, but not in other functions #1694

Boris-Rasin opened this issue Feb 15, 2019 · 5 comments · Fixed by #2048

Comments

@Boris-Rasin
Copy link
Contributor

Boris-Rasin commented Feb 15, 2019

struct example {
    example(std::string&&) {}
    void name(std::string&&) {}
};

pybind11::class_<example>(m, "example")
    .def(pybind11::init<std::string&&>()) // this works
    .def<void(example::*)(std::string&&)>("name", &example::name) // this doesn't
;

Error message:

/usr/local/include/pybind11/pybind11.h:72:74: error: rvalue reference to type 'basic_string<...>' cannot bind to lvalue of type 'basic_string<...>'
initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); },

@e00E
Copy link

e00E commented Jun 25, 2019

Here is another example:

#include <pybind11/pybind11.h>

namespace py = pybind11;

class C {
public:
  C() = default;
  void f(std::string &&) {}
};

PYBIND11_MODULE(frame_comparer, m) {
  py::class_<C>(m, "C")
    .def(py::init<>())
    .def("f", &C::f);
}

fails with:

usr/include/pybind11/pybind11.h:79:74: error: rvalue reference to type 'basic_string<...>' cannot bind to lvalue of type
      'basic_string<...>'
        initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); },
                                                                         ^~~~
/usr/include/pybind11/pybind11.h:1112:22: note: in instantiation of function template specialization
      'pybind11::cpp_function::cpp_function<void, C, std::__cxx11::basic_string<char> &&, pybind11::name, pybind11::is_method,
      pybind11::sibling>' requested here
        cpp_function cf(method_adaptor<type>(std::forward<Func>(f)), name(name_), is_method(*this),
                     ^
pybind.cpp:13:43: note: in instantiation of function template specialization 'pybind11::class_<C>::def<void
      (C::*)(std::__cxx11::basic_string<char> &&)>' requested here
  py::class_<C>(m, "C").def(py::init<>()).def("f", &C::f);

Maybe a good way to solve this is to allow syntax along the lines of:

...
.def_with_this("f", [](C* this_, std::string argument) { return this_->f(std::move(argument)); });

where the first argument is always the this pointer. This is terser than the workaround of defining a whole wrapper class and cleaner than the other workaround of making a non member wrappper.

@amrit-poudel
Copy link

amrit-poudel commented Mar 9, 2020

What exactly is the solution to this issue (identified by the op)? I am also encountering similar error.
Does anyone have a working solution that they could share here?I'd appreciate it.
Thanks.

Update:
.def_static("f", [](C* this_, std::string argument) { return this_->f(std::move(argument)); });
seems to be the workaround. Note def_with_this does not seem to work.
Also, why is string not passed by reference in the above fix? Is there a specific reason behind it?
.def_static("f", [](C* this_, std::string& argument) { return this_->f(std::move(argument)); });

@Boris-Rasin
Copy link
Contributor Author

This pull request seems to fix the problem, but for some reason it hasn't been merged:
#2048

@amrit-poudel
Copy link

amrit-poudel commented Mar 10, 2020

Thanks for that note. A bit off topic, but I was wondering if you know how I can expose operator() from a c++ class to python. I tried:

.def(“__call__”, &SomeClass::operator(), py::arg(“e”)=nullptr, py::is_operator());

This does not quite work.

@mattgodbolt
Copy link

I'm not sure the constructor works either: I think behind the scenes the compiler's using the copy constructor. In my tests with move-only types, a constructor taking a rvalue reference to an uncopyable type causes:

env/include/pybind11/detail/init.h:173:66: note:   conversion of argument 2 would be ill-formed:
In file included from env/include/pybind11/attr.h:13:0,
                 from env/include/pybind11/pybind11.h:44,
                 from ../src/python/pywave.cpp:5:
env/include/pybind11/cast.h:1982:37: error: cannot bind rvalue reference of type 'wave::TypeRegistry&&' to lvalue of type 'wave::TypeRegistry'
         return std::forward<Func>(f)(cast_op<Args>(std::move(std::get<Is>(argcasters)))...);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants