boost::bind and Motif
Hi, I just tried to use boost::bind to create a function pointer from an object method to define it as a Motif callback function: class AnimationController { public: void timerCB( XtPointer, XtIntervalId* ); void startTimer() { this->mTimeout = XtAppAddTimeOut( this->mAppContext, ANIMATION_TIMESTEP, boost::bind( &AnimationController::timerCB, this ), NULL ); } ... }; For the definition of the Motif function: XtIntervalId XtAppAddTimeOut( XtAppContext /* app_context */, unsigned long /* interval */, XtTimerCallbackProc /* proc */, XtPointer /* closure */ ); with typedef void (*XtTimerCallbackProc)( XtPointer /* closure */, XtIntervalId* /* id */ ); But I get the following error: ../AnimationController.cpp: In member function 'void geo::AnimationController::startTimer()': ../AnimationController.cpp:193: error: cannot convert 'boost::_bi::bind_t<void (&)(void*, XtIntervalId*), boost::_mfi::dm<void ()(void*, XtIntervalId*), geo::AnimationController>, boost::_bi::list1<boost::_bi::value<geo::AnimationController*> > >' to 'void (*)(void*, XtIntervalId*)' for argument '3' to 'XtIntervalId XtAppAddTimeOut(_XtAppStruct*, long unsigned int, void (*)(void*, XtIntervalId*), void*)' Can someone explain, what I did wrong? Thanks, Sven
I just tried to use boost::bind to create a function pointer from an object method to define it as a Motif callback function:
class AnimationController { public: void timerCB( XtPointer, XtIntervalId* ); void startTimer() { this->mTimeout = XtAppAddTimeOut( this->mAppContext, ANIMATION_TIMESTEP, boost::bind( &AnimationController::timerCB, this ), NULL ); } ... };
For the definition of the Motif function: XtIntervalId XtAppAddTimeOut( XtAppContext /* app_context */, unsigned long /* interval */, XtTimerCallbackProc /* proc */, XtPointer /* closure */ );
with
typedef void (*XtTimerCallbackProc)( XtPointer /* closure */, XtIntervalId* /* id */ );
But I get the following error:
../AnimationController.cpp: In member function 'void geo::AnimationController::startTimer()': ../AnimationController.cpp:193: error: cannot convert 'boost::_bi::bind_t<void (&)(void*, XtIntervalId*), boost::_mfi::dm<void ()(void*, XtIntervalId*), geo::AnimationController>, boost::_bi::list1<boost::_bi::value<geo::AnimationController*> > >' to 'void (*)(void*, XtIntervalId*)' for argument '3' to 'XtIntervalId XtAppAddTimeOut(_XtAppStruct*, long unsigned int, void (*)(void*, XtIntervalId*), void*)'
Bind creates a function object, while XtAppAddTimeOut expects a function pointer, as you mentioned. You can define a static member function that matches XtTimerCallbackProc signature, and pass it without bind.
Bind creates a function object, while XtAppAddTimeOut expects a function pointer, as you mentioned. You can define a static member function that matches XtTimerCallbackProc signature, and pass it without bind. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Thanks, that was the way i did it before. But from a static member function i have no access to the object attributes, so i had to make it a singleton class that was what i wanted to prevent by using bind.
Bind creates a function object, while XtAppAddTimeOut expects a function pointer, as you mentioned. You can define a static member function that matches XtTimerCallbackProc signature, and pass it without bind. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
Thanks, that was the way i did it before. But from a static member function i have no access to the object attributes, so i had to make it a singleton class that was what i wanted to prevent by using bind.
No, you don't have to make a signleton. The function XtAppAddTimeOut accepts "XtPointer client_data" argument, where you can pass "this". Then you get it back in the callback function, and type-cast it to its original type.
No, you don't have to make a signleton. The function XtAppAddTimeOut accepts "XtPointer client_data" argument, where you can pass "this". Then you get it back in the callback function, and type-cast it to its original type.
Ok this is another solution. But I don't like such pointer casts. I have done it the following way: class AnimationController { private: static boost::optional<AnimationController&> cInstance; public: static AnimationController& instance() { return cInstance.get(); } AnimationController() { cInstance = *this; } static void timerCB() { instance().animate(); } private: void animate(); }; Just as praise for boost::optional :-) Sven
On Thursday, May 03, 2012 4:56 AM, Sven Bauhan wrote:
No, you don't have to make a signleton. The function XtAppAddTimeOut accepts "XtPointer client_data" argument, where you can pass "this". Then you get it back in the callback function, and type-cast it to its original type.
Ok this is another solution. But I don't like such pointer casts. I have done it the following way:
class AnimationController { private: static boost::optional<AnimationController&> cInstance; public: static AnimationController& instance() { return cInstance.get(); } AnimationController() { cInstance = *this; } static void timerCB() { instance().animate(); } private: void animate(); };
Just as praise for boost::optional :-) Sven
The implementation that comes to my mind involves the following helper class or something similar (warning: untested): //A generic wrapper for XtAppAddTimeOut class AppTimeout { public: typedef boost::function <void()> CallbackType; //Constructor registers the app_context and callback, but doesn't start the timer. AppTimeout (XtAppContext app_context, CallbackType callback): app_context (app_context), callback (callback), interval_id (0) {} ~AppTimeout() { Cancel(); //Because the timer would cause undefined behavior if it triggers after the destructor } void Schedule (unsigned long interval) { assert (!interval_id); //This class only supports one timeout per instance interval_id = XtAppAddTimeOut (app_context, interval, &interval_callback, this); } void Cancel() { if (interval_id) //I won't consider redundant calls to Cancel an error; just no effect { XtRemoveTimeOut (interval_id); interval_id = 0; } } bool Is_pending() const {return interval_id != 0;} private: XtAppContext app_context; CallbackType callback; XtIntervalId interval_id; static void Internal_callback (XtPointer self, XtIntervalId*) { reinterpret_cast <AppTimeout*> (self)->callback(); //According to http://www.xfree86.org/current/XtAppAddTimeOut.3.html //a triggered timeout is automatically removed, so clear its id. reinterpret_cast <AppTimeout*> (self)->interval_id = 0; } };
[Please do not mail me a copy of your followup] boost-users@lists.boost.org spake the secret code <1D97E025367AFB4A8C528590A3715BF442603A@archerysummit2.willamette.charteroaksystems.com> thusly:
static void Internal_callback (XtPointer self, XtIntervalId*) { reinterpret_cast <AppTimeout*> (self)->callback();
I don't know why people always leap to reinterpret_cast<> as their first choice; it's the most dangerous. I'd prefer static_cast<> here. -- "The Direct3D Graphics Pipeline" -- DirectX 9 version available for download <http://legalizeadulthood.wordpress.com/the-direct3d-graphics-pipeline/> Legalize Adulthood! <http://legalizeadulthood.wordpress.com>
On Thursday, May 03, 2012 2:42 PM, Richard wrote:
boost-users@lists.boost.org spake the secret code <1D97E025367AFB4A8C528590A3715BF442603A@archerysummit2.willamette.charte roaksystems.com> thusly:
static void Internal_callback (XtPointer self, XtIntervalId*) { reinterpret_cast <AppTimeout*> (self)->callback();
I don't know why people always leap to reinterpret_cast<> as their first choice; it's the most dangerous. I'd prefer static_cast<> here.
In this case, the reinterpret_cast is needed because X11 specified that your callback *must* take a void pointer. Reinterpret_cast and the old c-style cast (which would act as a reinterpret_cast in this case) are the only ways I know to convert a void pointer to the correct type. In this case, I mitigated the danger by making Internal_callback private and ensuring the only place where it is used--the public Schedule function--provides a pointer of the correct type.
[Please do not mail me a copy of your followup] boost-users@lists.boost.org spake the secret code <1D97E025367AFB4A8C528590A3715BF442603B@archerysummit2.willamette.charteroaksystems.com> thusly:
On Thursday, May 03, 2012 2:42 PM, Richard wrote:
boost-users@lists.boost.org spake the secret code <1D97E025367AFB4A8C528590A3715BF442603A@archerysummit2.willamette.charte roaksystems.com> thusly:
static void Internal_callback (XtPointer self, XtIntervalId*) { reinterpret_cast <AppTimeout*> (self)->callback();
I don't know why people always leap to reinterpret_cast<> as their first choice; it's the most dangerous. I'd prefer static_cast<> here.
In this case, the reinterpret_cast is needed because X11 specified that your callback *must* take a void pointer.
static_cast<T*>(p) where p is void* works perfectly fine. It is always valid to cast a void* to any other type and that's what static_cast<> does -- performs the cast when it is allowed by the rules of the language. You don't need reinterpret_cast<> here. Did you try it with static_cast? See "C++ Coding Standards" by Sutter and Alexandrescu, items: 92. Avoid using reinterpret_cast 95. Don't use C-style casts -- "The Direct3D Graphics Pipeline" -- DirectX 9 version available for download <http://legalizeadulthood.wordpress.com/the-direct3d-graphics-pipeline/> Legalize Adulthood! <http://legalizeadulthood.wordpress.com>
On Fri, May 04, 2012 at 05:04:00PM +0000, Richard wrote:
static_cast<T*>(p) where p is void* works perfectly fine. It is always valid to cast a void* to any other type and that's what static_cast<> does -- performs the cast when it is allowed by the rules of the language.
Might it be C that allows arbitrary casts, but only guarantees proper semantics if the type is the correct one? My C-fu is weak, and I know they differ in what they allow. -- Lars Viklund | zao@acc.umu.se
[Please do not mail me a copy of your followup] boost-users@lists.boost.org spake the secret code <20120505152720.GD12377@honecker.acc.umu.se> thusly:
On Fri, May 04, 2012 at 05:04:00PM +0000, Richard wrote:
static_cast<T*>(p) where p is void* works perfectly fine. It is always valid to cast a void* to any other type and that's what static_cast<> does -- performs the cast when it is allowed by the rules of the language.
Might it be C that allows arbitrary casts, but only guarantees proper semantics if the type is the correct one?
static_cast<> is purely a C++ construct and is not present in C. -- "The Direct3D Graphics Pipeline" -- DirectX 9 version available for download <http://legalizeadulthood.wordpress.com/the-direct3d-graphics-pipeline/> Legalize Adulthood! <http://legalizeadulthood.wordpress.com>
On Friday, May 04, 2012 1:04 PM, Richard wrote:
static_cast<T*>(p) where p is void* works perfectly fine. It is always valid to cast a void* to any other type and that's what static_cast<> does -- performs the cast when it is allowed by the rules of the language.
You don't need reinterpret_cast<> here.
Did you try it with static_cast?
You learn something new every day. Since static_cast works, then feel free to change my sample accordingly. As for your earlier comment about the only "sane" thing being to cast back to the exact same type after a void* context parameter, that's the main reason why I suggested a generic helper class. My class takes complete control of the Xt callback, thus making it extremely difficult to mess up that cast, and it provides a type-safe interface to your code. Get it working once, and then reuse it whenever you need an XtAppTimeout.
[Please do not mail me a copy of your followup] boost-users@lists.boost.org spake the secret code <1D97E025367AFB4A8C528590A3715BF4426048@archerysummit2.willamette.charteroaksystems.com> thusly:
As for your earlier comment about the only "sane" thing being to cast
I don't think that was me who first remarked about it being the only sane thing to do, but I agree with the statement.
back to the exact same type after a void* context parameter, that's the main reason why I suggested a generic helper class. My class takes complete control of the Xt callback, thus making it extremely difficult to mess up that cast, and it provides a type-safe interface to your code. Get it working once, and then reuse it whenever you need an XtAppTimeout.
Yes, I agree. Whenever I am writing C++ code that must deal with void* mechanisms, the first thing I do is shove that void* behind some sort of helper class or function that quarantines the void* to the smallest scope possible. -- "The Direct3D Graphics Pipeline" -- DirectX 9 version available for download <http://legalizeadulthood.wordpress.com/the-direct3d-graphics-pipeline/> Legalize Adulthood! <http://legalizeadulthood.wordpress.com>
On Fri, May 4, 2012 at 6:33 AM, Andrew Holden <aholden@charteroaksystems.com
wrote:
On Thursday, May 03, 2012 2:42 PM, Richard wrote:
boost-users@lists.boost.org spake the secret code <1D97E025367AFB4A8C528590A3715BF442603A@archerysummit2.willamette.charte roaksystems.com> thusly:
static void Internal_callback (XtPointer self, XtIntervalId*) { reinterpret_cast <AppTimeout*> (self)->callback();
I don't know why people always leap to reinterpret_cast<> as their first choice; it's the most dangerous. I'd prefer static_cast<> here.
In this case, the reinterpret_cast is needed because X11 specified that your callback *must* take a void pointer. Reinterpret_cast and the old c-style cast (which would act as a reinterpret_cast in this case) are the only ways I know to convert a void pointer to the correct type. In this case, I mitigated the danger by making Internal_callback private and ensuring the only place where it is used--the public Schedule function--provides a pointer of the correct type.
Sorry, drifting off-topic, and I'm not sure what XtPointer is, but based on your comment above, it seems it is a void pointer, and you can indeed static_cast a void pointer to any other (object) pointer type (as long as you don't drop cv qualifiers). - Jeff
On Fri, May 04, 2012 at 11:42:58AM -0700, Jeffrey Lee Hellrung, Jr. wrote:
Sorry, drifting off-topic, and I'm not sure what XtPointer is, but based on your comment above, it seems it is a void pointer, and you can indeed static_cast a void pointer to any other (object) pointer type (as long as you don't drop cv qualifiers).
In my last standard reading, the conclusion I came to was that the only cast through void that is sane is the one to the exact same type, or possibly to/from char. -- Lars Viklund | zao@acc.umu.se
On Fri, May 4, 2012 at 12:53 PM, Lars Viklund <zao@acc.umu.se> wrote:
On Fri, May 04, 2012 at 11:42:58AM -0700, Jeffrey Lee Hellrung, Jr. wrote:
Sorry, drifting off-topic, and I'm not sure what XtPointer is, but based on your comment above, it seems it is a void pointer, and you can indeed static_cast a void pointer to any other (object) pointer type (as long as you don't drop cv qualifiers).
In my last standard reading, the conclusion I came to was that the only cast through void that is sane is the one to the exact same type, or possibly to/from char.
Sorry, right, I was referring strictly to a syntactic context, but the semantics is also important. - Jeff
[Please do not mail me a copy of your followup] boost-users@lists.boost.org spake the secret code <20120504195312.GC12377@honecker.acc.umu.se> thusly:
On Fri, May 04, 2012 at 11:42:58AM -0700, Jeffrey Lee Hellrung, Jr. wrote:
Sorry, drifting off-topic, and I'm not sure what XtPointer is, but based on your comment above, it seems it is a void pointer, and you can indeed static_cast a void pointer to any other (object) pointer type (as long as you don't drop cv qualifiers).
In my last standard reading, the conclusion I came to was that the only cast through void that is sane is the one to the exact same type, or possibly to/from char.
Yes, this is the only one that is "sane", but it's not the only one that's allowed by the language. This business of C style callbacks taking a void* context parameter has been around for a very very long time. I remember doing it back with Xt/Motif in 1989. The "sane" thing to do is to make sure that you cast it back to the exact type you passed in when you registered the callback with Xt. The best way to express this in C++ is static_cast<>. -- "The Direct3D Graphics Pipeline" -- DirectX 9 version available for download <http://legalizeadulthood.wordpress.com/the-direct3d-graphics-pipeline/> Legalize Adulthood! <http://legalizeadulthood.wordpress.com>
participants (6)
-
Andrew Holden
-
Igor R
-
Jeffrey Lee Hellrung, Jr.
-
Lars Viklund
-
legalize+jeeves@mail.xmission.com
-
Sven Bauhan