Boost Python return reference to cast input parameter not working with virtual function
up vote
0
down vote
favorite
I wrap the template classes A and B through boost python, and try to cast between them. I implement the toB function and wrap it with return_internal_reference<> to achieve this. However, it doesn't return the B object in python, but returns the "dead" A object, of which member function can't be used anymore.
I narrow down the problem, which is the virtual function in the base class, Bar. The toB function correctly returns the B object referencing to A object if I remove the virtual keyword for hi(). But, what is the correct way to do this? Why does the virtual function in the base class affect the outcome? On the other hand, is there a way to cast boost python wrapping classes directly in Python?
#include <boost/python.hpp>
#include <iostream>
using namespace boost::python;
struct Bar
{
virtual void hi() { std::cout << "Hi Bar." << std::endl; }
virtual ~Bar() {}
};
template<typename T>
struct Foo : Bar
{
void set(T v) { val = v; }
T get() { return val; }
private:
T val;
};
using A = Foo<unsigned short>;
using B = Foo<short>;
B & toB(A & a) { return *reinterpret_cast<B*>(&a);}
BOOST_PYTHON_MODULE(example)
{
class_<A>("A")
.def("set", &A::set)
.def("get", &A::get)
;
class_<B>("B")
.def("set", &B::set)
.def("get", &B::get)
;
def("toB", &toB, return_internal_reference<>());
}
Python execution
>>> from example import *
>>> a = A()
>>> toB(a)
<example.A object at 0x7f7139cd27c0>
>>> toB(a).get()
Traceback (most recent call last):
File "<stdin>", line 1 in <module>
Boost.Python.ArgumentError: Python argument types in
A.get(A)
did not match C++ signature:
get(Foo<unsigned int> {lvalue})
It works well if I remove the virtual keywords in Bar.
struct Bar
{
void hi() { std::cout << "Hi Bar." << std::endl; }
};
>>> from example import *
>>> a = A()
>>> toB(a)
<example.B object at 0x7f511000c7c0>
>>> toB(a).get()
>>> 4.484155085839415e-44
python c++ boost boost-python
|
show 1 more comment
up vote
0
down vote
favorite
I wrap the template classes A and B through boost python, and try to cast between them. I implement the toB function and wrap it with return_internal_reference<> to achieve this. However, it doesn't return the B object in python, but returns the "dead" A object, of which member function can't be used anymore.
I narrow down the problem, which is the virtual function in the base class, Bar. The toB function correctly returns the B object referencing to A object if I remove the virtual keyword for hi(). But, what is the correct way to do this? Why does the virtual function in the base class affect the outcome? On the other hand, is there a way to cast boost python wrapping classes directly in Python?
#include <boost/python.hpp>
#include <iostream>
using namespace boost::python;
struct Bar
{
virtual void hi() { std::cout << "Hi Bar." << std::endl; }
virtual ~Bar() {}
};
template<typename T>
struct Foo : Bar
{
void set(T v) { val = v; }
T get() { return val; }
private:
T val;
};
using A = Foo<unsigned short>;
using B = Foo<short>;
B & toB(A & a) { return *reinterpret_cast<B*>(&a);}
BOOST_PYTHON_MODULE(example)
{
class_<A>("A")
.def("set", &A::set)
.def("get", &A::get)
;
class_<B>("B")
.def("set", &B::set)
.def("get", &B::get)
;
def("toB", &toB, return_internal_reference<>());
}
Python execution
>>> from example import *
>>> a = A()
>>> toB(a)
<example.A object at 0x7f7139cd27c0>
>>> toB(a).get()
Traceback (most recent call last):
File "<stdin>", line 1 in <module>
Boost.Python.ArgumentError: Python argument types in
A.get(A)
did not match C++ signature:
get(Foo<unsigned int> {lvalue})
It works well if I remove the virtual keywords in Bar.
struct Bar
{
void hi() { std::cout << "Hi Bar." << std::endl; }
};
>>> from example import *
>>> a = A()
>>> toB(a)
<example.B object at 0x7f511000c7c0>
>>> toB(a).get()
>>> 4.484155085839415e-44
python c++ boost boost-python
Use a dynamic_cast, not a reinterpret_cast. You also forgot about the virtual destructors.
– Matthieu Brucher
Nov 6 at 14:56
B is not the base class of A. The user defined conversion from A to B is not defined. I am not sure if it's possible to defined a conversion so that the static_cast from a reference to A to a reference to B can happen.
– Alex Pai
Nov 6 at 15:43
Oh, actually, it's even worse... Basically, you are trying to read your unsigned as a float?? They may not even have the same size.
– Matthieu Brucher
Nov 6 at 15:45
Sorry, that's just an example. The real case is to casting between two very large template classes with same data size and different member functions. Updated the template type to short and unsigned short. But I think that's not related to the boost python issue.
– Alex Pai
Nov 6 at 15:52
Still a very bad idea, use a union instead.
– Matthieu Brucher
Nov 6 at 18:10
|
show 1 more comment
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I wrap the template classes A and B through boost python, and try to cast between them. I implement the toB function and wrap it with return_internal_reference<> to achieve this. However, it doesn't return the B object in python, but returns the "dead" A object, of which member function can't be used anymore.
I narrow down the problem, which is the virtual function in the base class, Bar. The toB function correctly returns the B object referencing to A object if I remove the virtual keyword for hi(). But, what is the correct way to do this? Why does the virtual function in the base class affect the outcome? On the other hand, is there a way to cast boost python wrapping classes directly in Python?
#include <boost/python.hpp>
#include <iostream>
using namespace boost::python;
struct Bar
{
virtual void hi() { std::cout << "Hi Bar." << std::endl; }
virtual ~Bar() {}
};
template<typename T>
struct Foo : Bar
{
void set(T v) { val = v; }
T get() { return val; }
private:
T val;
};
using A = Foo<unsigned short>;
using B = Foo<short>;
B & toB(A & a) { return *reinterpret_cast<B*>(&a);}
BOOST_PYTHON_MODULE(example)
{
class_<A>("A")
.def("set", &A::set)
.def("get", &A::get)
;
class_<B>("B")
.def("set", &B::set)
.def("get", &B::get)
;
def("toB", &toB, return_internal_reference<>());
}
Python execution
>>> from example import *
>>> a = A()
>>> toB(a)
<example.A object at 0x7f7139cd27c0>
>>> toB(a).get()
Traceback (most recent call last):
File "<stdin>", line 1 in <module>
Boost.Python.ArgumentError: Python argument types in
A.get(A)
did not match C++ signature:
get(Foo<unsigned int> {lvalue})
It works well if I remove the virtual keywords in Bar.
struct Bar
{
void hi() { std::cout << "Hi Bar." << std::endl; }
};
>>> from example import *
>>> a = A()
>>> toB(a)
<example.B object at 0x7f511000c7c0>
>>> toB(a).get()
>>> 4.484155085839415e-44
python c++ boost boost-python
I wrap the template classes A and B through boost python, and try to cast between them. I implement the toB function and wrap it with return_internal_reference<> to achieve this. However, it doesn't return the B object in python, but returns the "dead" A object, of which member function can't be used anymore.
I narrow down the problem, which is the virtual function in the base class, Bar. The toB function correctly returns the B object referencing to A object if I remove the virtual keyword for hi(). But, what is the correct way to do this? Why does the virtual function in the base class affect the outcome? On the other hand, is there a way to cast boost python wrapping classes directly in Python?
#include <boost/python.hpp>
#include <iostream>
using namespace boost::python;
struct Bar
{
virtual void hi() { std::cout << "Hi Bar." << std::endl; }
virtual ~Bar() {}
};
template<typename T>
struct Foo : Bar
{
void set(T v) { val = v; }
T get() { return val; }
private:
T val;
};
using A = Foo<unsigned short>;
using B = Foo<short>;
B & toB(A & a) { return *reinterpret_cast<B*>(&a);}
BOOST_PYTHON_MODULE(example)
{
class_<A>("A")
.def("set", &A::set)
.def("get", &A::get)
;
class_<B>("B")
.def("set", &B::set)
.def("get", &B::get)
;
def("toB", &toB, return_internal_reference<>());
}
Python execution
>>> from example import *
>>> a = A()
>>> toB(a)
<example.A object at 0x7f7139cd27c0>
>>> toB(a).get()
Traceback (most recent call last):
File "<stdin>", line 1 in <module>
Boost.Python.ArgumentError: Python argument types in
A.get(A)
did not match C++ signature:
get(Foo<unsigned int> {lvalue})
It works well if I remove the virtual keywords in Bar.
struct Bar
{
void hi() { std::cout << "Hi Bar." << std::endl; }
};
>>> from example import *
>>> a = A()
>>> toB(a)
<example.B object at 0x7f511000c7c0>
>>> toB(a).get()
>>> 4.484155085839415e-44
python c++ boost boost-python
python c++ boost boost-python
edited Nov 6 at 20:41
asked Nov 6 at 14:54
Alex Pai
437
437
Use a dynamic_cast, not a reinterpret_cast. You also forgot about the virtual destructors.
– Matthieu Brucher
Nov 6 at 14:56
B is not the base class of A. The user defined conversion from A to B is not defined. I am not sure if it's possible to defined a conversion so that the static_cast from a reference to A to a reference to B can happen.
– Alex Pai
Nov 6 at 15:43
Oh, actually, it's even worse... Basically, you are trying to read your unsigned as a float?? They may not even have the same size.
– Matthieu Brucher
Nov 6 at 15:45
Sorry, that's just an example. The real case is to casting between two very large template classes with same data size and different member functions. Updated the template type to short and unsigned short. But I think that's not related to the boost python issue.
– Alex Pai
Nov 6 at 15:52
Still a very bad idea, use a union instead.
– Matthieu Brucher
Nov 6 at 18:10
|
show 1 more comment
Use a dynamic_cast, not a reinterpret_cast. You also forgot about the virtual destructors.
– Matthieu Brucher
Nov 6 at 14:56
B is not the base class of A. The user defined conversion from A to B is not defined. I am not sure if it's possible to defined a conversion so that the static_cast from a reference to A to a reference to B can happen.
– Alex Pai
Nov 6 at 15:43
Oh, actually, it's even worse... Basically, you are trying to read your unsigned as a float?? They may not even have the same size.
– Matthieu Brucher
Nov 6 at 15:45
Sorry, that's just an example. The real case is to casting between two very large template classes with same data size and different member functions. Updated the template type to short and unsigned short. But I think that's not related to the boost python issue.
– Alex Pai
Nov 6 at 15:52
Still a very bad idea, use a union instead.
– Matthieu Brucher
Nov 6 at 18:10
Use a dynamic_cast, not a reinterpret_cast. You also forgot about the virtual destructors.
– Matthieu Brucher
Nov 6 at 14:56
Use a dynamic_cast, not a reinterpret_cast. You also forgot about the virtual destructors.
– Matthieu Brucher
Nov 6 at 14:56
B is not the base class of A. The user defined conversion from A to B is not defined. I am not sure if it's possible to defined a conversion so that the static_cast from a reference to A to a reference to B can happen.
– Alex Pai
Nov 6 at 15:43
B is not the base class of A. The user defined conversion from A to B is not defined. I am not sure if it's possible to defined a conversion so that the static_cast from a reference to A to a reference to B can happen.
– Alex Pai
Nov 6 at 15:43
Oh, actually, it's even worse... Basically, you are trying to read your unsigned as a float?? They may not even have the same size.
– Matthieu Brucher
Nov 6 at 15:45
Oh, actually, it's even worse... Basically, you are trying to read your unsigned as a float?? They may not even have the same size.
– Matthieu Brucher
Nov 6 at 15:45
Sorry, that's just an example. The real case is to casting between two very large template classes with same data size and different member functions. Updated the template type to short and unsigned short. But I think that's not related to the boost python issue.
– Alex Pai
Nov 6 at 15:52
Sorry, that's just an example. The real case is to casting between two very large template classes with same data size and different member functions. Updated the template type to short and unsigned short. But I think that's not related to the boost python issue.
– Alex Pai
Nov 6 at 15:52
Still a very bad idea, use a union instead.
– Matthieu Brucher
Nov 6 at 18:10
Still a very bad idea, use a union instead.
– Matthieu Brucher
Nov 6 at 18:10
|
show 1 more comment
1 Answer
1
active
oldest
votes
up vote
0
down vote
Exposed classes A
and B
don't provide all necessary information about their structure to python. Specifically that they derive from class Bar
.
To fix the problem expose also class Bar
to python and inform Boost.Python of the inheritance relationship between Bar
and A
and between Bar
and B
:
BOOST_PYTHON_MODULE(example)
{
class_<Bar>("Bar")
.def("hi", &Bar::hi)
;
class_<A, bases<Bar>>("A")
.def("set", &A::set)
.def("get", &A::get)
;
class_<B, bases<Bar>>("B")
.def("set", &B::set)
.def("get", &B::get)
;
def("toB", &toB, return_internal_reference<>());
}
After that is done everything should work as expected:
>>> from example import *
>>> a=A()
>>> b=toB(a)
>>> b.get()
0
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
Exposed classes A
and B
don't provide all necessary information about their structure to python. Specifically that they derive from class Bar
.
To fix the problem expose also class Bar
to python and inform Boost.Python of the inheritance relationship between Bar
and A
and between Bar
and B
:
BOOST_PYTHON_MODULE(example)
{
class_<Bar>("Bar")
.def("hi", &Bar::hi)
;
class_<A, bases<Bar>>("A")
.def("set", &A::set)
.def("get", &A::get)
;
class_<B, bases<Bar>>("B")
.def("set", &B::set)
.def("get", &B::get)
;
def("toB", &toB, return_internal_reference<>());
}
After that is done everything should work as expected:
>>> from example import *
>>> a=A()
>>> b=toB(a)
>>> b.get()
0
add a comment |
up vote
0
down vote
Exposed classes A
and B
don't provide all necessary information about their structure to python. Specifically that they derive from class Bar
.
To fix the problem expose also class Bar
to python and inform Boost.Python of the inheritance relationship between Bar
and A
and between Bar
and B
:
BOOST_PYTHON_MODULE(example)
{
class_<Bar>("Bar")
.def("hi", &Bar::hi)
;
class_<A, bases<Bar>>("A")
.def("set", &A::set)
.def("get", &A::get)
;
class_<B, bases<Bar>>("B")
.def("set", &B::set)
.def("get", &B::get)
;
def("toB", &toB, return_internal_reference<>());
}
After that is done everything should work as expected:
>>> from example import *
>>> a=A()
>>> b=toB(a)
>>> b.get()
0
add a comment |
up vote
0
down vote
up vote
0
down vote
Exposed classes A
and B
don't provide all necessary information about their structure to python. Specifically that they derive from class Bar
.
To fix the problem expose also class Bar
to python and inform Boost.Python of the inheritance relationship between Bar
and A
and between Bar
and B
:
BOOST_PYTHON_MODULE(example)
{
class_<Bar>("Bar")
.def("hi", &Bar::hi)
;
class_<A, bases<Bar>>("A")
.def("set", &A::set)
.def("get", &A::get)
;
class_<B, bases<Bar>>("B")
.def("set", &B::set)
.def("get", &B::get)
;
def("toB", &toB, return_internal_reference<>());
}
After that is done everything should work as expected:
>>> from example import *
>>> a=A()
>>> b=toB(a)
>>> b.get()
0
Exposed classes A
and B
don't provide all necessary information about their structure to python. Specifically that they derive from class Bar
.
To fix the problem expose also class Bar
to python and inform Boost.Python of the inheritance relationship between Bar
and A
and between Bar
and B
:
BOOST_PYTHON_MODULE(example)
{
class_<Bar>("Bar")
.def("hi", &Bar::hi)
;
class_<A, bases<Bar>>("A")
.def("set", &A::set)
.def("get", &A::get)
;
class_<B, bases<Bar>>("B")
.def("set", &B::set)
.def("get", &B::get)
;
def("toB", &toB, return_internal_reference<>());
}
After that is done everything should work as expected:
>>> from example import *
>>> a=A()
>>> b=toB(a)
>>> b.get()
0
answered Nov 8 at 11:01
doqtor
6,3851927
6,3851927
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53174370%2fboost-python-return-reference-to-cast-input-parameter-not-working-with-virtual-f%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Use a dynamic_cast, not a reinterpret_cast. You also forgot about the virtual destructors.
– Matthieu Brucher
Nov 6 at 14:56
B is not the base class of A. The user defined conversion from A to B is not defined. I am not sure if it's possible to defined a conversion so that the static_cast from a reference to A to a reference to B can happen.
– Alex Pai
Nov 6 at 15:43
Oh, actually, it's even worse... Basically, you are trying to read your unsigned as a float?? They may not even have the same size.
– Matthieu Brucher
Nov 6 at 15:45
Sorry, that's just an example. The real case is to casting between two very large template classes with same data size and different member functions. Updated the template type to short and unsigned short. But I think that's not related to the boost python issue.
– Alex Pai
Nov 6 at 15:52
Still a very bad idea, use a union instead.
– Matthieu Brucher
Nov 6 at 18:10