[bind] virtual function pointer woes

Imagine I have a base class B with a virtual function f() that is overridden in a derived class D ... struct B { virtual void f() { std::printf("B\n"); } }; struct D : B { virtual void f() { std::printf("D\n"); } }; Now, I can have a derived object D and call the base member directly using qualification: D d; d.B::f(); // OK, called B::f But if I take the address of B::f for use with boost::bind, I get a thunk that always uses virtual dispatch... boost::bind( &B::f, _1 )( d ); // Hrm, calls D::f What if I don't want the virtual dispatch, and I really want this to behave like d.B::f()? I know this is not specifically a problem with boost::bind, but a more general property of (virtual) member function pointers. Is there any way to get a non-virtual member function pointer to a virtual member function? If there is a way, I'm sure I don't know it. -- Eric Niebler BoostPro Computing http://www.boostpro.com

As far as I know, no. If you find a true answer, please tell me. I had this problem once as well and looked into it on the newsgroups. There may be a non-portable way with the vtable and asm, but not generally. My suggestion would be to make a split _nv function that does the call struct B { virtual void f() { f_nv(); } void f_nv() {std::printf("B\n"); } }; struct D : B { virtual void f() { f_nv(); } void f_nv() { std::printf("D\n"); } }; And then bind _nv; Eric Niebler wrote:
Imagine I have a base class B with a virtual function f() that is overridden in a derived class D ...
struct B { virtual void f() { std::printf("B\n"); } }; struct D : B { virtual void f() { std::printf("D\n"); } };
Now, I can have a derived object D and call the base member directly using qualification:
D d; d.B::f(); // OK, called B::f
But if I take the address of B::f for use with boost::bind, I get a thunk that always uses virtual dispatch...
boost::bind( &B::f, _1 )( d ); // Hrm, calls D::f
What if I don't want the virtual dispatch, and I really want this to behave like d.B::f()?
I know this is not specifically a problem with boost::bind, but a more general property of (virtual) member function pointers. Is there any way to get a non-virtual member function pointer to a virtual member function? If there is a way, I'm sure I don't know it.

Chris wrote:
As far as I know, no. If you find a true answer, please tell me. I had this problem once as well and looked into it on the newsgroups. There may be a non-portable way with the vtable and asm, but not generally. My suggestion would be to make a split
_nv function that does the call
struct B { virtual void f() { f_nv(); } void f_nv() {std::printf("B\n"); } }; struct D : B { virtual void f() { f_nv(); } void f_nv() { std::printf("D\n"); } };
And then bind _nv;
Or just create a new free function: inline void call_B_f(D &d) { d->B::f(); } boost::bind(&call_B_f, _1)(d); -- Jon Biggar jon@biggar.org jon@floorboard.com

Jon Biggar wrote:
Chris wrote:
As far as I know, no. If you find a true answer, please tell me. I had this problem once as well and looked into it on the newsgroups. There may be a non-portable way with the vtable and asm, but not generally. My suggestion would be to make a split
_nv function that does the call
struct B { virtual void f() { f_nv(); } void f_nv() {std::printf("B\n"); } }; struct D : B { virtual void f() { f_nv(); } void f_nv() { std::printf("D\n"); } };
And then bind _nv;
This is not an option as the classes B and D are not modifiable.
Or just create a new free function:
inline void call_B_f(D &d) { d->B::f(); }
boost::bind(&call_B_f, _1)(d);
Sure, but I'm going to need a lot of these little functions and it's a pain. C++ has what I want (the member function I want to bind to), but it's not giving it to me. Very frustrating. -- Eric Niebler BoostPro Computing http://www.boostpro.com

Did c++0x address this? Here is a macro example, call MAKE_CALL_BASE(thefunc); for every virtual function. #include <iostream> struct B { virtual void f() { std::printf("B\n"); } }; struct D : B { virtual void f() { std::printf("D\n"); } }; #define MAKE_CALL_BASE(X) \ template <typename BASE, typename... Args> \ void call_##X(BASE *d, Args... args) \ { \ d->BASE::X (args...); \ } MAKE_CALL_BASE(f); int main() { B * b = new D; call_f<B>(b); } Eric Niebler wrote:
Jon Biggar wrote:
Chris wrote:
As far as I know, no. If you find a true answer, please tell me. I had this problem once as well and looked into it on the newsgroups. There may be a non-portable way with the vtable and asm, but not generally. My suggestion would be to make a split
_nv function that does the call
struct B { virtual void f() { f_nv(); } void f_nv() {std::printf("B\n"); } }; struct D : B { virtual void f() { f_nv(); } void f_nv() { std::printf("D\n"); } };
And then bind _nv;
This is not an option as the classes B and D are not modifiable.
Or just create a new free function:
inline void call_B_f(D &d) { d->B::f(); }
boost::bind(&call_B_f, _1)(d);
Sure, but I'm going to need a lot of these little functions and it's a pain. C++ has what I want (the member function I want to bind to), but it's not giving it to me. Very frustrating.
participants (3)
-
Chris
-
Eric Niebler
-
Jon Biggar