I'm using pybind11 to create python bindings for a C++ library whose source I cannot change. It contains a class that defines member functions with rvalue reference arguments (eg T &&val). I am unable to create a binding to a member function with rvalue reference arguments but binding to a non-member function with identical arguments works as expected.
A simplified example looks like this:
struct Foo {
// Cannot create a pybinding for this method.
void print_ref(int &&v) const {
std::cout << "Foo::print_ref(" << to_string(v) << ")" <<std::endl;
}
};
// Pybinding for standalone function works as expected.
void print_ref(int&& val) {
std::cout << "print_ref(" << to_string(val) << ")" << std::endl;
};
The pybind11 code looks like this:
PYBIND11_MODULE(refref, m) {
py::class_<Foo>(m, "Foo")
// Both of these attempts to create a pybinding FAILs with same error.
.def("print_ref", &Foo::print_ref)
.def("print_ref", (void (Foo::*) (int&&)) &Foo::print_ref);
// This pybinding of standalone function is SUCCESSful.
m.def("print_ref", &print_ref);
}
The compilation error on the first binding attempt is:
pybind11/bin/../include/site/python3.4/pybind11/pybind11.h:79:80: error: rvalue reference to type 'int' cannot bind to lvalue of type 'int'
initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); },
^~~~
pybind11/bin/../include/site/python3.4/pybind11/pybind11.h:1085:22: note: in instantiation of function template specialization 'pybind11::cpp_function::cpp_function<void, Foo, int &&,
pybind11::name, pybind11::is_method, pybind11::sibling>' requested here
cpp_function cf(method_adaptor<type>(std::forward<Func>(f)), name(name_), is_method(*this),
^
refref.cpp:31:3: note: in instantiation of function template specialization 'pybind11::class_<Foo>::def<void (Foo::*)(int &&) const>' requested here
.def("print_ref", &Foo::print_ref);
Any ideas on what I may be doing wrong? Since it works fine with non-member functions, I'm inclined to suspect a pybind11 issue but thought I would check here first.
Indeed, the problem comes from rvalues. I learned quite a few things from this SO answer and this blog post.
There's a nice workaround : you can create a wrapper class that will redirect calls to the C++ library you cannot change, taking care of the rvalue with the std::move semantic.
#include <iostream>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
struct Foo {
void print_ref(int&& v) const {
std::cout << "Foo::print_ref(" << +v << ")" <<std::endl;
}
};
// This class will interface between PyBind and your library
class Foo_wrap{
private:
Foo _mimu;
public:
void print_ref(int v) const{
_mimu.print_ref(std::move(v));
}
};
PYBIND11_MODULE(example, m) {
py::class_<Foo_wrap>(m, "Foo_wrap")
.def(py::init())
.def("print_ref", &Foo_wrap::print_ref);
}
That you can call in Python with
import example as fo
wr = fo.Foo_wrap()
wr.print_ref(2)
Related
We are trying to write a really simple class, for complex numbers jsut as an example, and we do not get very far...
Below is our 3 files.
complex2.h
#include<iostream>
#include<new>
template<class T>
class complex2
{
private:
T re, im; // real and imaginary part
public:
complex2();
complex2(T re_a =0.0, T im_a =0.0); //= 0.0 = 0.0
~complex2() {}
T Re () const;
T Im () const;
};
#endif // COMPLEX2_H
complex2.cpp
#include "complex2.h"
template<class T>
complex2<T>:: complex2 () {re = im = 0.0; }
template<class T>
complex2<T>:: complex2(T re_a, T im_a){re = re_a; im = im_a;}
template<class T> T complex2<T>:: Re() const { return re;}
template<class T> T complex2<T>:: Im() const {return im;}
main.cpp
#include <iostream>
#include<cmath>
#include"complex2.h"
using namespace std;
int main()
{
complex2<int> b(1, 2);//
cout << "Re b: "<< b.Re() << "Im b: "<< b.Im() << endl;
return 0;
}
Running the above from Qt, gives the error messages
/home...main.cpp:10: error: undefined reference to `complex2<int>::complex2(int, int)'
/home/.../main.cpp:11: error: undefined reference to `complex2<int>::Im() const'
/home/...main.cpp:11: error: undefined reference to `complex2<int>::Re() const'
:-1: error: collect2: error: ld returned 1 exit status
Does anybody see how we can make this work?
I think this post solves your problem: Why can templates only be implemented in the header file?
The way in which template classes are split between header and source is somehow tricky...
Regards
My question is: how do I pass a class member function into for_each
Code I am trying to get to work: (works when function is defined outside of class)
The part which fails is commented out - the one using for_each with function as the class member function
Any advice on how to get this to work?
#include <iostream>
#include <algorithm>
#include <vector>
void my_function(std::string str)
{
std::cout << "processing settings: " << str << std::endl;
}
class Settings_vector{
public:
std::vector <std::string> settings;
Settings_vector(){ // push back vector of objects
settings.push_back("settings 1");
settings.push_back("settings 2");
settings.push_back("settings 3");
settings.push_back("settings 4");
}
void tester(std::string settings_string){
std::cout << "processing settings: " << settings_string << std::endl;
}
};
int main()
{
//std::vector<std::string> my_vector;
Settings_vector settings_vector;
std:: cout << "doing things the non-class way\n" << std::endl;
for_each(settings_vector.settings.begin(), settings_vector.settings.end(), my_function); // testing function
// WORKS
/*
std:: cout << "doing things the modern way\n" << std::endl;
for_each(settings_vector.settings.begin(), settings_vector.settings.end(), settings_vector.tester); // testing function
// FAILS
*/
std:: cout << "doing things the oldskool way\n" << std::endl;
for (int i = 0;i<settings_vector.settings.size();++i) {
settings_vector.tester(settings_vector.settings[i]);
}
// WORKS
return 0;
}
The easiest way would be to use a lambda expression. A bit more complex approach is to use std::bind() to bind all known arguments (here the instance of the class to the member function) and leave unknown arguments with placeholders _1, _2, etc.
#include <iostream>
#include <algorithm>
#include <vector>
class Settings_vector
{
Settings_vector()
: settings { "settings 1"
, "settings 2"
, "settings 3"
, "settings 4"
}
{}
void tester(std::string settings_string)
{ std::cout << "processing settings: " << settings_string << std::endl; }
public:
std::vector <std::string> settings;
};
int main()
{
Settings_vector settings_vector;
using namespace std;
using namespace std::placeholders; // for _1
// Possibility Nr. 1: Use a Lambda Function
for_each( settings_vector.settings.begin(), settings_vector.settings.end()
, [&settings_vector](auto input){ settings_vector.tester(input); }
)
;
// Possibility Nr. 2: Partially bind existing arguments and use placeholders for others
for_each( settings_vector.settings.begin(), settings_vector.settings.end()
, std::bind(&Settings_vector::tester, &settings_vector, _1);
)
;
return 0;
}
Explanations:
I think a lambda is straight forward. In the square brackets, you declare what goes into a closure. Here we pass settings_vector. Preceding it with & means that this instance is passed by reference. In the parenthesis, we declare the parameters to the function. I cheated a little bit, as auto in lambda expressions was introduced in C++14, but you can write it as type std::string as well.
std::bind() binds parameters to a function pointer and returns a callable object. If all parameters are present, the returned callable has no parameters and can be called like: callable(). Here, we want a callable to accept the result of the iteration. Thus, we use a placeholder _1, which states that this argument will be changed at call-time. Now 2 things remain:
Getting a pointer to a member function. This is done by using &TypeName::MemberName, in this case &Settings_vector::tester.
Passing a this pointer to a member function call: &settings_vector. When calling a member function, an object must be passed for which this member function is called. Because we just got a pointer to a member function without any bound object to it, that's why the second param is &settings_vector.
For a more concise sintax, use a static class method. I've slightly edited your code for improved readability within the context of your question (aka removing distractions).
#include <iostream>
#include <vector>
class Settings {
public:
std::vector <std::string> settings;
Settings(std::initializer_list<std::string> l)
: settings(l) {
}
static void tester(std::string const& str) {
std::cout << "processing settings: " << str << std::endl;
}
};
int main() {
Settings sv {"settings 1", "settings 2", "settings 3", "settings 4"};
for_each(sv.settings.begin(), sv.settings.end(), Settings::tester);
return 0;
}
So here's my code I'm working with:
#include <iostream>
class Node
{
public:
void speak(){std::cout << "I'm a base node" << std::endl;}
};
class Child : public Node
{
public:
void speak(){std::cout << "I'm a child node" << std::endl;}
};
int main()
{
Node node;
Child child;
node.speak();
child.speak();
std::cout << "= Pointers..." << std::endl;
Node* pnode = &node;
Node* pchild = &child;
pnode->speak();
pchild->speak();
}
And here's the output:
I'm a base node
I'm a child node
= Pointers...
I'm a base node
I'm a base node
The pchild->speak(); calls the Node's method and not the Child's one.
Now my problem is that I may have many different types of nodes, with varying number of connections. Thus I cannot declare a member pointer with a ChildX class, but only with a generic Node class. But each node will have a certain method that I want called.
I've tried to have a pointer to that method itself instead of to the class (since it would always be int (*foo)() type), but the compiler complains about invalid use of non-static member function.
So both of my approaches don't work. Neither pointer to a class, nor pointer to classes member function.
Familiarize yourself with virtual functions and polymorphism - both key concepts in c++.
In your question you simply need to define
virtual void speak(){std::cout << "I'm a base/child node" << std::endl;}
I would like to overload the << operator for my class from a method display already defined. I get an compiler error of no match for operator <<.
Here is a minimal example:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{}
ostream& display(ostream& out) const
{
out << "Display message" << endl;
return out;
}
ostream& operator<< (ostream& out) const
{
ostream& output = display(out);
return output;
}
};
int main()
{
MyClass C1;
cout << C1 << endl;
return 0;
}
Although C1.display(cout); woks without problems!
You have defined operator<< as a member function of MyClass. Therefore, you must call it like member functions are called (object on the left, parameter on the right), like this:
C1 << cout;
But that doesn't seem to be what you want. You probably want to be able to call it like this:
cout << C1;
In that case the function can't be a member of MyClass. It would have to be a member of cout, or a free function (outside any class). And in this case it must be a free function because you can't change the definition of cout.
So, to declare operator<< as a free function, it needs to have two arguments (left-hand-side and right-hand-side):
ostream& operator<< (ostream& out, const MyClass& c) { ... }
Now you can call it with an ostream on the left and a MyClass object on the right, like this:
cout << C1;
I am reading about copy constructor.
can any body tell me what is happening in the below statement
class Base {
public:
Base() {cout << "Base constructor";}
Base(const Base& a) {cout << "copy constructor with const arg";}
Base(Base& a) {cout << "copy constructor with non-const arg"; return a;}
const Base& operator=(Base &a) {cout << "assignment operator with non-const arg"; return a;}
}
void main()
{
Base a;
Base b = Base(); // This is neither calling copy constructor nor assignment operator.
}
Please tell me what is happening at "Base b = Base()" statement.
Copy constructor will be called in three casess:
When an object is returned by value
When an object is passed (to a function) by value as an argument
When an object is thrown
When an object is caught
When an object is placed in a brace-enclosed initializer list
assignment opertator will be called when below:
B b;
b=a;
so your statement:
Base b = Base();
does not suit any of the above.