This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Callback Library Submitted by

One way to write generic code is the use of callbacks. Callbacks allow one module to interact with another module without knowing of that module. It calls blindly the function that the other module has hooked to the callback of the former. We all know how to use function pointers for that. But that only works for global functions. But what if we want to use a specific method of a specific object as callback? Function pointers do no longer work. Although you can have pointers to methods, you can't hold the specified object in. So you have to find another way. Here, I'll show you one way to do it.
So, you also want so explanation? Let's try it with an little example. Say we have a lamp and a switch. All lamps have two states: on and off. We want to use a switch to control the state of the lamp. Not just any lamp, now we want to control the state of THE lamp.

    class Lamp
    {
    public:
        Lamp(): m_state(false) {}
        void setState(bool a_on) { m_state = a_on; }
    private:
        bool m_state;
    }

    Lamp theLamp;

One way to do it, would be to store inside the switch a pointer to the lamp, and hardcode the state control.

    class Switch
    {
    public:
        Switch(Lamp* a_lamp): m_lamp(a_lamp), m_pressed(false) {}
        void press()
        {
            m_pressed = !m_pressed;
            m_lamp-setState(m_pressed);
        }
    private:
        Lamp* m_lamp;
        bool m_pressed;
    }

    Switch switch(&theLamp);
    switch.press();

But that's of course not very flexible. What if the lamp has another fancy method we want to call? Then we would need change all switches. A way to deal with that, is using function pointers:

    typedef void (Lamp::*LampMethod)(bool);

    class Switch
    {
    public:
        Switch(Lamp* a_lamp, LampMethod a_method):
            m_lamp(a_lamp), m_method(a_method), m_pressed(false) {}
        void press()
        {
            m_pressed = !m_pressed;
            (m_lamp-*m_method)(m_pressed);
        }
    private:
        Lamp* m_lamp;
        LampMethod m_method;
        bool m_pressed;
    }

    Switch switch(&theLamp, Lamp::setState);
    switch.press();

But again, that's not flexible enough. The switch is still dedicated to lamps. What if one day you want to control an electrical fan with it? Then you need to change the switches again. And still, the switch needs to know about the lamps and the fans to do this callback thingy. What we really want is to store the necessary information of the object (and its class) in the function pointer too. So, we want something like this (Note: this is no valid C++!):

    class Switch
    {
    public:
        Switch(Something a_something):
            m_something(a_something), m_pressed(false) {}
        void press()
        {
            m_pressed = !m_pressed;
            m_something(m_pressed);
        }
    private:
        Something m_something;
    }

    Switch switch(theLamp.setState);
    switch.press();

One way to translate this to real C++ is to use some polymorphism. Let Something be nothing but a pointer to a pure virtual base class DispBase. You derive from that base class another class DispMethod that can hold an object and a function pointer (of course very templated). Then, you let that pointer point to a DispMethod, while it thinks it actually points to a DispBase. Thanks to some virtual functions the pointer will call the method of that object without knowing. Well, it's harder to explain than it is. So you should look inside Callback0.h and Callback0Detail.h. These are the easiest ones. (Notice that Callback0 doesn't take a parameter as it does in the switch example. For the switch, we'll need a Callback1. But later more on this). Callback0 encapsulates that pointer (and plays the role of Something :) DispBase is the base class (Disp stands for dispatcher), DispMethod will be able to handle an object/method pair, DispMethodConst is needed if we want to use constant methods, and DispFunction is also added. DispFunction can take a normal non-member function. That way, the callback system can also work as before with plain function pointers. The Maker functions are used to generate a callback from it's parameters. The benefits of a function is that you don't need to specify the typenames for the template. The compiler will try to guess them. Anyway, with all this stuff, the switch story becomes the following:

    #include "Callback1.h"

    class Switch
    {
    public:
        Switch(Callback1 a_callback):
            m_callback(a_callback), m_pressed(false) {}
        void press()
        {
            m_pressed = !m_pressed;
            m_callback(m_pressed);
        }
    private:
        Callback1 m_callback;
    }

    Lamp theLamp;
    Switch switch1(makeCallback1(&theLamp, Lamp::setState));
    Switch switch2(makeCallback1(&theLamp, Lamp::fancyMethod));
    Switch switch3(makeCallback1(&theFan, Fan::turn));

You can easily see that Switch doesn't care of what type the callback will be. We can easily hook Lamps and Fans on it, and the Switch will never notice. And this, all thanks to some virtual functions and a bunch of templates. One problem with templates is that we don't have a "variable number of typenames" thingy. That means that we need different callback classes for callbacks that take no parameters, one parameter, two parameters ... This reflects in the number behind the name: Callback0 is a callback that takes no parameters, Callback1 takes one parameter. I didn't implement Callback2 yet because I didn't need it yet, but you should be able to do it yourself. The other problem is that there's also a big difference between callbacks that do return a value, and callbacks that don't. You can't solve this with templates neighter, so that's why you need yet another version of callback to handle this. Callbacks with R's can return a value, Callbacks without can't. An overview of what I've implemented:
Callback0: no return value, no parameters.
Callback1: no return value, 1 parameter.
CallbackR0: return value, no paramters.
CallbackR1: return value, 1 parameter.
As I already said before, I didn't implement callbacks with more parameters, but it should be easy to do that.
In the templates, typenames for return values are called R, typenames for parameters are called P1, P2, ... e.g. the template for CallbackR1 looks as the following: template<typename R, typename P1> class CallbackR1;
Notice that you only need to include headers like Callback0.h, Callback1.h, ... The others contain only details and are not directly used by the clients of these callbacks. There's also a test program, but that's pretty crappy. The only thing I know of it, is that it tests stuff and that the tests are positive. So, don't bother about it. :)
Notice also that I've used boost::shared_ptr (http://www.boost.org/libs/smart_ptr/index.htm) for these Callback thingies. If this is a problem, you can always change it. But I suggest you install boost (http://www.boost.org) anyway. It's such a great thing :)
That's somewhat all there's to say about this. The other stuff you can read in the headers themselfes I guess. I Thank you for your time and I hope somebody will find this useful. I especially want to thank Jape & Altair for teaching me how to write "proper" C++ code. Thanks :)
Update 11 june 2002: You know what? I've written this library originally because I couldn't find anything else that did this job. I even looked in Boost, but I couldn't find anything. Now it seems I didn't look carefully enough. So, here I stood: having implemented a feature that was already in Boost by using another feature of Boost: boost::shared_ptr. Wasn't that silly? Yes it was. So, I decided to get rid of boost::shared_ptr in this library so that regained its value. And thanks to Dirk Gerrits, it gained a lot of more: safety. It's still a tiny Callback Library that might suit your needs, but now it doesn't depend on Boost anymore, the last implementation detail is removed from the public interface, it throws exceptions when something goes wrong, and it is more flexible now. You can hook a function that returns an integer to a callback with a float as return value, and a lot more. Also, the makers are gone and replaced by templated constructors, conversion to bool is gone and isEmpty() is now called empty(). Thanks again Dirk to help me on this (actually, all changes were his ideas, but sssst, don't tell anyone :). Soit, we officially have now reached BriDGe::Callback 2.00 :) Enjoy!
Kind regards,
Bram "Bramz" de Greve

Currently browsing [callback.zip] (32,820 bytes) - [Callback0.h] - (8,309 bytes)

    /*----------------------------------------------------------------------------*
     | Headerfile Callback0.h                                                     |
     |                                                                            |
     | Version 2.00                                                               |
     |                                                                            |
     |                                                                            |
     | BriDGe::Callback: a tiny library that provides callback functionality.     |
     | Copyright (C) 2002  Bram de Greve                                          |
     |                                                                            |
     | This library is free software; you can redistribute it and/or              |
     | modify it under the terms of the GNU Lesser General Public                 |
     | License as published by the Free Software Foundation; either               |
     | version 2.1 of the License, or (at your option) any later version.         |
     |                                                                            |
     | This library is distributed in the hope that it will be useful,            |
     | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
     | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
     | Lesser General Public License for more details.                            |
     |                                                                            |
     | You should have received a copy of the GNU Lesser General Public           |
     | License along with this library; if not, write to the Free Software        |
     | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
     |                                                                            |
     |                                                                            |
     | Contact by e-mail: Bram de Greve <bdegreve@mail.be>                        |
     |                                                                            |
     |                                                                            |
     | History:                                                                   |
     | May 28th, 2002: Creation of Callback0.h                                    |
     | June 2th, 2002: Getting rid of interal compiler error.                     |
     |                 Yiha!  We've bypassed the system!  mwuahaha!  hihi :)      |
     | June 7th, 2002: Splitting Callback0 to multiple files.                     |
     | June 8th, 2002: Revamping the code.                                        |
     |                 Putting stuff under GNU LGPL.                              |
     | June 9th, 2002: Getting rid of boost::shared_ptr so we look less silly,    |
     |                 Getting rid of makeCallback since we use templated         |
     |                 constructors now.                                          |
     |                 Making the call of an empty callback a little more safe    |
     |                 by throwing an exception CallbackEmptyCall.                |
     |                 Getting rid of operator bool and renaming isEmpty to empty.|
     |                 And some other stuff too.  Thank you Dirk Gerrits!         |
     |                 Soit, we have now officially reached version 2.00!         |
     |                                                                            |
     | I want to thank Altair, Jaap Suter & especially Dirk Gerrits (Who has      |
     | spent an entire afternoon on this to help me.  It was a waste of time for  |
     | both of us, but we had a lot of fun, didn't we? :)                         |
     *----------------------------------------------------------------------------*/

    // HOW TO USE THIS:
    //
    // 1. You create a Callback0 by using a ... constructor.  Surprise, surprise!
    //    It used to be done by maker functions, but we have now templated
    //    constructors.  Very cool:
    //          void foo();
    //          Callback0 callback1(foo);
    //
    //          class Bar
    //          {
    //          public:
    //              void fun();
    //          }
    //          Bar bar;
    //          Callback0 callback2(bar, Bar::fun);
    //
    // 2. You can copy callback objects as much as you like.
    //          Callback0 callback3(callback1);
    //
    //          Callback0 callback4;
    //          callback4 = callback2;
    //
    // 3. To excecute the callback, you evoke the function operator
    //          callback1();
    //
    // Note: Although you can allocate callbacks without specifying the exact
    //       callback function, you must make sure the callback can do something
    //       when you excecute it.  So, you must feed it with appropriate beef
    //       (functions, object/method pair).  If you don't, funny things will
    //       happen.  A crash for example.  Luckely for you, a special exception
    //       BDG::CallbackEmptyCall will be thrown so that you can catch it.
    //       On the other hand, you could also have checked this before the call
    //       with the method empty().
    //          try
    //          {
    //              callback1();
    //          }
    //          catch (CallbackEmptyCall)
    //          {
    //              ...
    //          }
    //
    //          if (!callback1.empty())
    //          {
    //              callback1();
    //          }
    //
    // Note: If you use a object/method pair as callback, you must make sure the
    //       object is alive when calling the callback.  Otherwise the callback
    //       will want to do the method on dead beef, and you know funny things
    //       happen when it does that.  And you know what that means, don't you?

    #ifndef BDG_GUARDIAN_OF_INCLUSION_CALLBACK0_H
    #define BDG_GUARDIAN_OF_INCLUSION_CALLBACK0_H

    // --- OLD INTERFACES ----------------------------------------------------------

    #include "Callback0Detail.h"
    #include "CallbackExceptions.h"
    #include <algorithm>                    // std::swap

    // --- NEW INTERFACES ----------------------------------------------------------

    namespace BDG
    {

    // THE CALLBACK:
    // This is the actuall class you use to hold callbacks:

    class Callback0
    {
    public:

        // STRUCTORS

        Callback0():
            m_dispatcher(0)
        {
        }

        explicit Callback0(void (*a_function)())
        {
            if (!a_function) throw CallbackNullArgument(
                "BDG::Callback0: tried to construct from null function pointer.");
            using namespace Callback0_Detail;
            m_dispatcher = new DispFunction(a_function);
        }

        template<class Object>
        Callback0(Object* a_object, void (Object::*a_method)())
        {
            if (!(a_object && a_method)) throw CallbackNullArgument(
                "BDG::Callback0: tried to construct from null object or method "
                "pointer.");
            using namespace Callback0_Detail;
            m_dispatcher = new DispMethod<Object>(a_object, a_method);
        }

        template<class Object>
        Callback0(Object* a_object, void (Object::*a_method)() const)
        {
            if (!(a_object && a_method)) throw CallbackNullArgument(
                "BDG::Callback0: tried to construct from null object or method "
                "pointer.");
            using namespace Callback0_Detail;
            m_dispatcher = new DispMethodConst<Object>(a_object, a_method);
        }

        Callback0(const Callback0& a_other):
            m_dispatcher(a_other.empty() ? 0 : a_other.m_dispatcher->clone())
        {
        }

        // OPERATORS

        Callback0 operator=(const Callback0& a_other)
        {
            Callback0 temp(a_other);
            swap(temp);
            return *this;
        }

        void operator()() const
        {
            if (empty()) throw CallbackEmptyCall(
                "BDG::Callback0: tried to call an empty callback.");
            (*m_dispatcher)();
        }

        // METHODS

        bool empty() const
        {
            return m_dispatcher == 0;
        }

        void swap(Callback0& a_other)
        {
            std::swap(m_dispatcher, a_other.m_dispatcher);
        }

    private:

        Callback0_Detail::DispBase* m_dispatcher;
    };

    } // namespace BDG

    #endif // Guardian of Inclusion

    // --- END OF FILE Callback0.h -------------------------------------------------

Currently browsing [callback.zip] (32,820 bytes) - [Callback0Detail.h] - (5,720 bytes)

    /*----------------------------------------------------------------------------*
     | Headerfile Callback0Detail.h                                               |
     |                                                                            |
     | Version 2.00                                                               |
     |                                                                            |
     |                                                                            |
     | BriDGe::Callback: a tiny library that provides callback functionality.     |
     | Copyright (C) 2002  Bram de Greve                                          |
     |                                                                            |
     | This library is free software; you can redistribute it and/or              |
     | modify it under the terms of the GNU Lesser General Public                 |
     | License as published by the Free Software Foundation; either               |
     | version 2.1 of the License, or (at your option) any later version.         |
     |                                                                            |
     | This library is distributed in the hope that it will be useful,            |
     | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
     | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
     | Lesser General Public License for more details.                            |
     |                                                                            |
     | You should have received a copy of the GNU Lesser General Public           |
     | License along with this library; if not, write to the Free Software        |
     | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
     |                                                                            |
     |                                                                            |
     | Contact by e-mail: Bram de Greve <bdegreve@mail.be>                        |
     |                                                                            |
     |                                                                            |
     | History:                                                                   |
     | June 7th, 2002: Splitting Callback0 to multiple files.                     |
     |                 Creation of Callback0Detail.h                              |
     | June 8th, 2002: Revamping the code.                                        |
     |                 Putting stuff under GNU LGPL.                              |
     | June 9th, 2002: Getting rid of boost::shared_ptr so we look less silly,    |
     |                 Getting rid of makeCallback since we use templated         |
     |                 constructors now.                                          |
     |                 Making the call of an empty callback a little more safe    |
     |                 by throwing an exception CallbackEmptyCall.                |
     |                 Getting rid of operator bool and renaming isEmpty to empty.|
     |                 And some other stuff too.  Thank you Dirk Gerrits!         |
     |                 Soit, we have now officially reached version 2.00!         |
     |                                                                            |
     | I want to thank Altair, Jaap Suter & especially Dirk Gerrits (Who has      |
     | spent an entire afternoon on this to help me.  It was a waste of time for  |
     | both of us, but we had a lot of fun, didn't we? :)                         |
     *----------------------------------------------------------------------------*/

    #ifndef BDG_GUARDIAN_OF_INCLUSION_CALLBACK0DETAIL_H
    #define BDG_GUARDIAN_OF_INCLUSION_CALLBACK0DETAIL_H

    // --- NEW INTERFACES ----------------------------------------------------------

    namespace BDG
    {

    namespace Callback0_Detail
    {

    // Base class for dispatchers:

    class DispBase
    {
    public:

        virtual void operator()() const = 0;
        virtual DispBase* clone() const = 0;
    };

    // Dispatcher to a non-member function:

    class DispFunction: public DispBase
    {
    private:

        typedef void (*Function) ();
        Function m_function;

    public:

        DispFunction(Function a_function):
            m_function(a_function)
        {
        }

        void operator()() const
        {
            (*m_function)();
        }

        DispBase* clone() const
        {
            return new DispFunction(*this);
        }
    };

    // Dispatcher to Object/Method pair:

    template <class Object>
    class DispMethod: public DispBase
    {
    private:

        typedef void (Object::*Method) ();

        Object* m_object;
        Method m_method;

    public:

        DispMethod(Object* a_object, Method a_method):
            m_object(a_object),
            m_method(a_method)
        {
        }

        void operator()() const
        {
            (m_object->*m_method)();
        }

        DispBase* clone() const
        {
            return new DispMethod(*this);
        }
    };

    // Dispatcher to Object/(const Method) pair:

    template <class Object>
    class DispMethodConst: public DispBase
    {
    private:

        typedef void (Object::*Method) () const;

        Object* m_object;
        Method m_method;

    public:

        DispMethodConst(Object* a_object, Method a_method):
            m_object(a_object),
            m_method(a_method)
        {
        }

        void operator()() const
        {
            (m_object->*m_method)();
        }

        DispBase* clone() const
        {
            return new DispMethodConst(*this);
        }
    };

    } // namespace Callback0_Detail

    } // namespace BDG

    #endif // Guardian of Inclusion

    // --- END OF FILE Callback0Detail.h -------------------------------------------

Currently browsing [callback.zip] (32,820 bytes) - [Callback1.h] - (8,494 bytes)

    /*----------------------------------------------------------------------------*
     | Headerfile Callback1.h                                                     |
     |                                                                            |
     | Version 2.00                                                               |
     |                                                                            |
     |                                                                            |
     | BriDGe::Callback: a tiny library that provides callback functionality.     |
     | Copyright (C) 2002  Bram de Greve                                          |
     |                                                                            |
     | This library is free software; you can redistribute it and/or              |
     | modify it under the terms of the GNU Lesser General Public                 |
     | License as published by the Free Software Foundation; either               |
     | version 2.1 of the License, or (at your option) any later version.         |
     |                                                                            |
     | This library is distributed in the hope that it will be useful,            |
     | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
     | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
     | Lesser General Public License for more details.                            |
     |                                                                            |
     | You should have received a copy of the GNU Lesser General Public           |
     | License along with this library; if not, write to the Free Software        |
     | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
     |                                                                            |
     |                                                                            |
     | Contact by e-mail: Bram de Greve <bdegreve@mail.be>                        |
     |                                                                            |
     |                                                                            |
     | History:                                                                   |
     | May 28th, 2002: creation of Callback1.h                                    |
     | June 2th, 2002: Getting rid of interal compiler error.                     |
     |                 Yiha!  We've bypassed the system!  mwuahaha!  hihi :)      |
     | June 7th, 2002: Splitting Callback1 to multiple files.                     |
     | June 8th, 2002: Revamping the code.                                        |
     |                 Putting stuff under GNU LGPL.                              |
     | June 9th, 2002: Getting rid of boost::shared_ptr so we look less silly,    |
     |                 Getting rid of makeCallback since we use templated         |
     |                 constructors now.                                          |
     |                 Making the call of an empty callback a little more safe    |
     |                 by throwing an exception CallbackEmptyCall.                |
     |                 Getting rid of operator bool and renaming isEmpty to empty.|
     |                 And some other stuff too.  Thank you Dirk Gerrits!         |
     |                 Soit, we have now officially reached version 2.00!         |
     |                                                                            |
     | I want to thank Altair, Jaap Suter & especially Dirk Gerrits (Who has      |
     | spent an entire afternoon on this to help me.  It was a waste of time for  |
     | both of us, but we had a lot of fun, didn't we? :)                         |
     *----------------------------------------------------------------------------*/

    // HOW TO USE THIS:
    //
    // 1. You create a Callback1 by using a ... constructor.  Surprise, surprise!
    //    It used to be done by maker functions, but we have now templated
    //    constructors.  Very cool:
    //          void foo(int a);
    //          Callback1<int> callback1(foo);
    //
    //          class Bar
    //          {
    //          public:
    //              void fun(int a);
    //          }
    //          Bar bar;
    //          Callback1<int> callback2(bar, Bar::fun);
    //
    // 2. You can copy callback objects as much as you like.
    //          Callback1<int> callback3(callback1);
    //
    //          Callback1<int> callback4;
    //          callback4 = callback2;
    //
    // 3. To excecute the callback, you evoke the function operator
    //          callback1(999);
    //
    // Note: Although you can allocate callbacks without specifying the exact
    //       callback function, you must make sure the callback can do something
    //       when you excecute it.  So, you must feed it with appropriate beef
    //       (functions, object/method pair).  If you don't, funny things will
    //       happen.  A crash for example.  Luckely for you, a special exception
    //       BDG::CallbackEmptyCall will be thrown so that you can catch it.
    //       On the other hand, you could also have checked this before the call
    //       with the method empty().
    //          try
    //          {
    //              callback1(999);
    //          }
    //          catch (CallbackEmptyCall)
    //          {
    //              ...
    //          }
    //
    //          if (!callback1.empty())
    //          {
    //              callback1(999);
    //          }
    //
    // Note: If you use a object/method pair as callback, you must make sure the
    //       object is alive when calling the callback.  Otherwise the callback
    //       will want to do the method on dead beef, and you know funny things
    //       happen when it does that.  And you know what that means, don't you?

    #ifndef BDG_GUARDIAN_OF_INCLUSION_CALLBACK1_H
    #define BDG_GUARDIAN_OF_INCLUSION_CALLBACK1_H

    // --- OLD INTERFACES ----------------------------------------------------------

    #include "Callback1Detail.h"
    #include "CallbackExceptions.h"
    #include <algorithm>                    // std::swap

    // --- NEW INTERFACES ----------------------------------------------------------

    namespace BDG
    {

    // THE CALLBACK:
    // This is the actuall class you use to hold callbacks:

    template<typename P1>
    class Callback1
    {
    public:

        // STRUCTORS

        Callback1():
            m_dispatcher(0)
        {
        }

        template<typename FP1>
        explicit Callback1(void (*a_function)(FP1))
        {
            if (!a_function) throw CallbackNullArgument(
                "BDG::Callback1: tried to construct from null function pointer.");
            using namespace Callback1_Detail;
            m_dispatcher = new DispFunction<P1, FP1>(a_function);
        }

        template<class Object, typename MP1>
        Callback1(Object* a_object, void (Object::*a_method)(MP1))
        {
            if (!(a_object && a_method)) throw CallbackNullArgument(
                "BDG::Callback1: tried to construct from null object or method "
                "pointer.");
            using namespace Callback1_Detail;
            m_dispatcher = new DispMethod<Object, P1, MP1>(a_object, a_method);
        }

        template<class Object, typename MP1>
        Callback1(Object* a_object, void (Object::*a_method)(MP1) const)
        {
            if (!(a_object && a_method)) throw CallbackNullArgument(
                "BDG::Callback1: tried to construct from null object or method "
                "pointer.");
            using namespace Callback1_Detail;
            m_dispatcher = new DispMethodConst<Object, P1, MP1>(a_object, a_method);
        }

        Callback1(const Callback1<P1>& a_other):
            m_dispatcher(a_other.empty() ? 0 : a_other.m_dispatcher->clone())
        {
        }

        // OPERATORS

        Callback1 operator=(const Callback1<P1>& a_other)
        {
            Callback1<P1> temp(a_other);
            swap(temp);
            return *this;
        }

        void operator()(P1 a_p1) const
        {
            if (empty()) throw CallbackEmptyCall(
                "BDG::Callback1: tried to call an empty callback.");
            (*m_dispatcher)(a_p1);
        }

        // METHODS

        bool empty() const
        {
            return m_dispatcher == 0;
        }

        void swap(Callback1<P1>& a_other)
        {
            std::swap(m_dispatcher, a_other.m_dispatcher);
        }

    private:

        Callback1_Detail::DispBase<P1>* m_dispatcher;
    };

    } // namespace BDG

    #endif // Guardian of Inclusion

    // --- END OF FILE Callback1.h -------------------------------------------------

Currently browsing [callback.zip] (32,820 bytes) - [Callback1Detail.h] - (5,947 bytes)

    /*----------------------------------------------------------------------------*
     | Headerfile Callback1Detail.h                                               |
     |                                                                            |
     | Version 1.20                                                               |
     |                                                                            |
     |                                                                            |
     | BriDGe::Callback: a tiny library that provides callback functionality.     |
     | Copyright (C) 2002  Bram de Greve                                          |
     |                                                                            |
     | This library is free software; you can redistribute it and/or              |
     | modify it under the terms of the GNU Lesser General Public                 |
     | License as published by the Free Software Foundation; either               |
     | version 2.1 of the License, or (at your option) any later version.         |
     |                                                                            |
     | This library is distributed in the hope that it will be useful,            |
     | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
     | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
     | Lesser General Public License for more details.                            |
     |                                                                            |
     | You should have received a copy of the GNU Lesser General Public           |
     | License along with this library; if not, write to the Free Software        |
     | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
     |                                                                            |
     |                                                                            |
     | Contact by e-mail: Bram de Greve <bdegreve@mail.be>                        |
     |                                                                            |
     |                                                                            |
     | History:                                                                   |
     | June 7th, 2002: Splitting Callback1 to multiple files.                     |
     |                 Creation of Callback1Detail.h                              |
     | June 8th, 2002: Revamping the code.                                        |
     |                 Putting stuff under GNU LGPL.                              |
     | June 9th, 2002: Getting rid of boost::shared_ptr so we look less silly,    |
     |                 Getting rid of makeCallback since we use templated         |
     |                 constructors now.                                          |
     |                 Making the call of an empty callback a little more safe    |
     |                 by throwing an exception CallbackEmptyCall.                |
     |                 Getting rid of operator bool and renaming isEmpty to empty.|
     |                 And some other stuff too.  Thank you Dirk Gerrits!         |
     |                 Soit, we have now officially reached version 2.00!         |
     |                                                                            |
     | I want to thank Altair, Jaap Suter & especially Dirk Gerrits (Who has      |
     | spent an entire afternoon on this to help me.  It was a waste of time for  |
     | both of us, but we had a lot of fun, didn't we? :)                         |
     *----------------------------------------------------------------------------*/

    #ifndef BDG_GUARDIAN_OF_INCLUSION_CALLBACK1DETAIL_H
    #define BDG_GUARDIAN_OF_INCLUSION_CALLBACK1DETAIL_H

    // --- NEW INTERFACES ----------------------------------------------------------

    namespace BDG
    {

    namespace Callback1_Detail
    {

    // Base class for dispatchers:

    template<typename P1>
    class DispBase
    {
    public:

        virtual void operator()(P1 a_p1) const = 0;
        virtual DispBase* clone() const = 0;
    };

    // Dispatcher to a non-member function:

    template<typename P1, typename FP1>
    class DispFunction: public DispBase<P1>
    {
    private:

        typedef void (*Function) (FP1);
        Function m_function;

    public:

        DispFunction(Function a_function):
            m_function(a_function)
        {
        }

        void operator()(P1 a_p1) const
        {
            (*m_function)(a_p1);
        }

        DispBase<P1>* clone() const
        {
            return new DispFunction<P1, FP1>(*this);
        }
    };

    // Dispatcher to Object/Method pair:

    template <class Object, typename P1, typename MP1>
    class DispMethod: public DispBase<P1>
    {
    private:

        typedef void (Object::*Method) (MP1);
        Object* m_object;
        Method m_method;

    public:

        DispMethod(Object* a_object, Method a_method):
            m_object(a_object),
            m_method(a_method)
        {
        }

        void operator()(P1 a_p1) const
        {
            (m_object->*m_method)(a_p1);
        }

        DispBase<P1>* clone() const
        {
            return new DispMethod<Object, P1, MP1>(*this);
        }
    };

    // Dispatcher to Object/(const Method) pair:

    template <class Object, typename P1, typename MP1>
    class DispMethodConst: public DispBase<P1>
    {
    private:

        typedef void (Object::*Method) (MP1) const;
        Object* m_object;
        Method m_method;

    public:

        DispMethodConst(Object* a_object, Method a_method):
            m_object(a_object),
            m_method(a_method)
        {
        }

        void operator()(P1 a_p1) const
        {
            (m_object->*m_method)(a_p1);
        }

        DispBase<P1>* clone() const
        {
            return new DispMethodConst<Object, P1, MP1>(*this);
        }
    };

    } // namespace Callback1_Detail

    } // namespace BDG

    #endif // Guardian of Inclusion

    // --- END OF FILE Callback1Detail.h -------------------------------------------

Currently browsing [callback.zip] (32,820 bytes) - [CallbackExceptions.h] - (3,626 bytes)

    /*----------------------------------------------------------------------------*
     | Headerfile CallbackEmptyCall.h                                             |
     |                                                                            |
     | Version 2.00                                                               |
     |                                                                            |
     | BriDGe::Callback: a tiny library that provides callback functionality.     |
     | Copyright (C) 2002  Bram de Greve                                          |
     |                                                                            |
     | This library is free software; you can redistribute it and/or              |
     | modify it under the terms of the GNU Lesser General Public                 |
     | License as published by the Free Software Foundation; either               |
     | version 2.1 of the License, or (at your option) any later version.         |
     |                                                                            |
     | This library is distributed in the hope that it will be useful,            |
     | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
     | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
     | Lesser General Public License for more details.                            |
     |                                                                            |
     | You should have received a copy of the GNU Lesser General Public           |
     | License along with this library; if not, write to the Free Software        |
     | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
     |                                                                            |
     |                                                                            |
     | Contact by e-mail: Bram de Greve <bdegreve@mail.be>                        |
     |                                                                            |
     |                                                                            |
     | History:                                                                   |
     | June 9th, 2002: Creation of CallbackEmptyCall.h.                           |
     |                                                                            |
     | I want to thank Altair, Jaap Suter & especially Dirk Gerrits (Who has      |
     | spent an entire afternoon on this to help me.  It was a waste of time for  |
     | both of us, but we had a lot of fun, didn't we? :)                         |
     *----------------------------------------------------------------------------*/

    #ifndef BDG_GUARDIAN_OF_INCLUSION_CALLBACKEMPTYCALL_H
    #define BDG_GUARDIAN_OF_INCLUSION_CALLBACKEMPTYCALL_H

    // --- OLD INTERFACES ----------------------------------------------------------

    #include <stdexcept>                    // std::runtime_error
    #include <string>                       // std::string

    // --- NEW INTERFACES ----------------------------------------------------------

    namespace BDG
    {

    struct CallbackEmptyCall : std::runtime_error
    {
    public:

        explicit CallbackEmptyCall(const std::string& a_string):
            std::runtime_error(a_string)
        {
        }
    };

    struct CallbackNullArgument : std::invalid_argument
    {
    public:

        explicit CallbackNullArgument(const std::string& a_string):
            std::invalid_argument(a_string)
        {
        }
    };

    } // namespace BDG

    #endif // Guardian of Inclusion

    // --- END OF FILE CallbackEmptyCall.h -----------------------------------------

Currently browsing [callback.zip] (32,820 bytes) - [CallbackR0.h] - (8,505 bytes)

    /*----------------------------------------------------------------------------*
     | Headerfile CallbackR0.h                                                    |
     |                                                                            |
     | Version 2.00                                                               |
     |                                                                            |
     |                                                                            |
     | BriDGe::Callback: a tiny library that provides callback functionality.     |
     | Copyright (C) 2002  Bram de Greve                                          |
     |                                                                            |
     | This library is free software; you can redistribute it and/or              |
     | modify it under the terms of the GNU Lesser General Public                 |
     | License as published by the Free Software Foundation; either               |
     | version 2.1 of the License, or (at your option) any later version.         |
     |                                                                            |
     | This library is distributed in the hope that it will be useful,            |
     | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
     | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
     | Lesser General Public License for more details.                            |
     |                                                                            |
     | You should have received a copy of the GNU Lesser General Public           |
     | License along with this library; if not, write to the Free Software        |
     | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
     |                                                                            |
     |                                                                            |
     | Contact by e-mail: Bram de Greve <bdegreve@mail.be>                        |
     |                                                                            |
     |                                                                            |
     | History:                                                                   |
     | May 28th, 2002: creation of CallbackR0.h                                   |
     | June 2th, 2002: Getting rid of interal compiler error.                     |
     |                 Yiha!  We've bypassed the system!  mwuahaha!  hihi :)      |
     | June 7th, 2002: Splitting CallbackR0 to multiple files.                    |
     | June 8th, 2002: Revamping the code.                                        |
     |                 Putting stuff under GNU LGPL.                              |
     | June 9th, 2002: Getting rid of boost::shared_ptr so we look less silly,    |
     |                 Getting rid of makeCallback since we use templated         |
     |                 constructors now.                                          |
     |                 Making the call of an empty callback a little more safe    |
     |                 by throwing an exception CallbackEmptyCall.                |
     |                 Getting rid of operator bool and renaming isEmpty to empty.|
     |                 And some other stuff too.  Thank you Dirk Gerrits!         |
     |                 Soit, we have now officially reached version 2.00!         |
     |                                                                            |
     | I want to thank Altair, Jaap Suter & especially Dirk Gerrits (Who has      |
     | spent an entire afternoon on this to help me.  It was a waste of time for  |
     | both of us, but we had a lot of fun, didn't we? :)                         |
     *----------------------------------------------------------------------------*/

    // HOW TO USE THIS:
    //
    // 1. You create a CallbackR0 by using a ... constructor.  Surprise, surprise!
    //    It used to be done by maker functions, but we have now templated
    //    constructors.  Very cool:
    //          int foo();
    //          CallbackR0<int> callback1(foo);
    //
    //          class Bar
    //          {
    //          public:
    //              int fun();
    //          }
    //          Bar bar;
    //          CallbackR0<int> callback2(bar, Bar::fun);
    //
    // 2. You can copy callback objects as much as you like.
    //          CallbackR0<int> callback3(callback1);
    //
    //          CallbackR0<int> callback4;
    //          callback4 = callback2;
    //
    // 3. To excecute the callback, you evoke the function operator
    //          int r = callback1();
    //
    // Note: Although you can allocate callbacks without specifying the exact
    //       callback function, you must make sure the callback can do something
    //       when you excecute it.  So, you must feed it with appropriate beef
    //       (functions, object/method pair).  If you don't, funny things will
    //       happen.  A crash for example.  Luckely for you, a special exception
    //       BDG::CallbackEmptyCall will be thrown so that you can catch it.
    //       On the other hand, you could also have checked this before the call
    //       with the method empty().
    //          try
    //          {
    //              int r = callback1();
    //          }
    //          catch (CallbackEmptyCall)
    //          {
    //              ...
    //          }
    //
    //          if (!callback1.empty())
    //          {
    //              int r = callback1();
    //          }
    //
    // Note: If you use a object/method pair as callback, you must make sure the
    //       object is alive when calling the callback.  Otherwise the callback
    //       will want to do the method on dead beef, and you know funny things
    //       happen when it does that.  And you know what that means, don't you?

    #ifndef BDG_GUARDIAN_OF_INCLUSION_CALLBACKR0_H
    #define BDG_GUARDIAN_OF_INCLUSION_CALLBACKR0_H

    // --- OLD INTERFACES ----------------------------------------------------------

    #include "CallbackR0Detail.h"
    #include "CallbackExceptions.h"
    #include <algorithm>                    // std::swap

    // --- NEW INTERFACES ----------------------------------------------------------

    namespace BDG
    {

    // THE CALLBACK:
    // This is the actuall class you use to hold callbacks:

    template <typename R>
    class CallbackR0
    {
    public:

        // CONSTRUCTORS & DESTRUCTORS

        CallbackR0():
            m_dispatcher(0)
        {
        }

        template<typename FR>
        explicit CallbackR0(FR (*a_function)())
        {
            if (!a_function) throw CallbackNullArgument(
                "BDG::CallbackR0: tried to construct from null function pointer.");
            using namespace CallbackR0_Detail;
            m_dispatcher = new DispFunction<R, FR>(a_function);
        }

        template<class Object, typename MR>
        CallbackR0(Object* a_object, MR (Object::*a_method)())
        {
            if (!(a_object && a_method)) throw CallbackNullArgument(
                "BDG::CallbackR0: tried to construct from null object or method "
                "pointer.");
            using namespace CallbackR0_Detail;
            m_dispatcher = new DispMethod<Object, R, MR>(a_object, a_method);
        }

        template<class Object, typename MR>
        CallbackR0(Object* a_object, MR (Object::*a_method)() const)
        {
            if (!(a_object && a_method)) throw CallbackNullArgument(
                "BDG::CallbackR0: tried to construct from null object or method "
                "pointer.");
            using namespace CallbackR0_Detail;
            m_dispatcher = new DispMethodConst<Object, R, MR>(a_object, a_method);
        }

        CallbackR0(const CallbackR0<R>& a_other):
            m_dispatcher(a_other.empty() ? 0 : a_other.m_dispatcher->clone())
        {
        }

        // OPERATORS

        CallbackR0 operator=(const CallbackR0<R>& a_other)
        {
            CallbackR0<R> temp(a_other);
            swap(temp);
            return *this;
        }

        R operator()() const
        {
            if (empty()) throw CallbackEmptyCall(
                "BDG::CallbackR0: tried to call an empty callback.");
            return (*m_dispatcher)();
        }

        // METHODS

        bool empty() const
        {
            return m_dispatcher == 0;
        }

        void swap(CallbackR0<R>& a_other)
        {
            std::swap(m_dispatcher, a_other.m_dispatcher);
        }

    private:

        CallbackR0_Detail::DispBase<R>* m_dispatcher;
    };

    } // namespace BDG

    #endif // Guardian of Inclusion

    // --- END OF FILE CallbackR0.h ------------------------------------------------

Currently browsing [callback.zip] (32,820 bytes) - [CallbackR0Detail.h] - (5,882 bytes)

    /*----------------------------------------------------------------------------*
     | Headerfile CallbackR0Detail.h                                              |
     |                                                                            |
     | Version 2.00                                                               |
     |                                                                            |
     |                                                                            |
     | BriDGe::Callback: a tiny library that provides callback functionality.     |
     | Copyright (C) 2002  Bram de Greve                                          |
     |                                                                            |
     | This library is free software; you can redistribute it and/or              |
     | modify it under the terms of the GNU Lesser General Public                 |
     | License as published by the Free Software Foundation; either               |
     | version 2.1 of the License, or (at your option) any later version.         |
     |                                                                            |
     | This library is distributed in the hope that it will be useful,            |
     | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
     | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
     | Lesser General Public License for more details.                            |
     |                                                                            |
     | You should have received a copy of the GNU Lesser General Public           |
     | License along with this library; if not, write to the Free Software        |
     | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
     |                                                                            |
     |                                                                            |
     | Contact by e-mail: Bram de Greve <bdegreve@mail.be>                        |
     |                                                                            |
     |                                                                            |
     | History:                                                                   |
     | June 7th, 2002: Splitting CallbackR0 to multiple files.                    |
     |                 Creation of CallbackR0Detail.h                             |
     | June 8th, 2002: Revamping the code.                                        |
     |                 Putting stuff under GNU LGPL.                              |
     | June 9th, 2002: Getting rid of boost::shared_ptr so we look less silly,    |
     |                 Getting rid of makeCallback since we use templated         |
     |                 constructors now.                                          |
     |                 Making the call of an empty callback a little more safe    |
     |                 by throwing an exception CallbackEmptyCall.                |
     |                 Getting rid of operator bool and renaming isEmpty to empty.|
     |                 And some other stuff too.  Thank you Dirk Gerrits!         |
     |                 Soit, we have now officially reached version 2.00!         |
     |                                                                            |
     | I want to thank Altair, Jaap Suter & especially Dirk Gerrits (Who has      |
     | spent an entire afternoon on this to help me.  It was a waste of time for  |
     | both of us, but we had a lot of fun, didn't we? :)                         |
     *----------------------------------------------------------------------------*/

    #ifndef BDG_GUARDIAN_OF_INCLUSION_CALLBACKR0DETAIL_H
    #define BDG_GUARDIAN_OF_INCLUSION_CALLBACKR0DETAIL_H

    // --- NEW INTERFACES ----------------------------------------------------------

    namespace BDG
    {

    namespace CallbackR0_Detail
    {

    // Base class for dispatchers:

    template<typename R>
    class DispBase
    {
    public:

        virtual R operator()() const = 0;
        virtual DispBase<R>* clone() const = 0;
    };

    // Dispatcher to a non-member function:

    template<typename R, typename FR>
    class DispFunction: public DispBase<R>
    {
    private:

        typedef FR (*Function) ();
        Function m_function;

    public:

        DispFunction(Function a_function):
            m_function(a_function)
        {
        }

        R operator()() const
        {
            return (*m_function)();
        }

        DispBase<R>* clone() const
        {
            return new DispFunction<R, FR>(*this);
        }
    };

    // Dispatcher to Object/Method pair:

    template<class Object, typename R, typename MR>
    class DispMethod: public DispBase<R>
    {
    private:

        typedef MR (Object::*Method) ();
        Object* m_object;
        Method m_method;

    public:

        DispMethod(Object* a_object, Method a_method):
            m_object(a_object),
            m_method(a_method)
        {
        }

        R operator()() const
        {
            return (m_object->*m_method)();
        }

        DispBase<R>* clone() const
        {
            return new DispMethod<Object, R, MR>(*this);
        }
    };

    // Dispatcher to Object/(const Method) pair:

    template <class Object, typename R, typename MR>
    class DispMethodConst: public DispBase<R>
    {
    private:

        typedef MR (Object::*Method) () const;
        Object* m_object;
        Method m_method;

    public:

        DispMethodConst(Object* a_object, Method a_method):
            m_object(a_object),
            m_method(a_method)
        {
        }

        R operator()() const
        {
            return (m_object->*m_method)();
        }

        DispBase<R>* clone() const
        {
            return new DispMethodConst<Object, R, MR>(*this);
        }
    };

    } // namespace CallbackR0_Detail

    } // namespace BDG

    #endif // Guardian of Inclusion

    // --- END OF FILE CallbackR0Detail.h ------------------------------------------

Currently browsing [callback.zip] (32,820 bytes) - [CallbackR1.h] - (8,799 bytes)

    /*----------------------------------------------------------------------------*
     | Headerfile CallbackR1.h                                                    |
     |                                                                            |
     | Version 2.00                                                               |
     |                                                                            |
     |                                                                            |
     | BriDGe::Callback: a tiny library that provides callback functionality.     |
     | Copyright (C) 2002  Bram de Greve                                          |
     |                                                                            |
     | This library is free software; you can redistribute it and/or              |
     | modify it under the terms of the GNU Lesser General Public                 |
     | License as published by the Free Software Foundation; either               |
     | version 2.1 of the License, or (at your option) any later version.         |
     |                                                                            |
     | This library is distributed in the hope that it will be useful,            |
     | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
     | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
     | Lesser General Public License for more details.                            |
     |                                                                            |
     | You should have received a copy of the GNU Lesser General Public           |
     | License along with this library; if not, write to the Free Software        |
     | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
     |                                                                            |
     |                                                                            |
     | Contact by e-mail: Bram de Greve <bdegreve@mail.be>                        |
     |                                                                            |
     |                                                                            |
     | History:                                                                   |
     | May 28th, 2002: creation of CallbackR1.h                                   |
     | June 2th, 2002: Getting rid of interal compiler error.                     |
     |                 Yiha!  We've bypassed the system!  mwuahaha!  hihi :)      |
     | June 7th, 2002: Splitting CallbackR1 to multiple files.                    |
     | June 8th, 2002: Revamping the code.                                        |
     |                 Putting stuff under GNU LGPL.                              |
     | June 9th, 2002: Getting rid of boost::shared_ptr so we look less silly,    |
     |                 Getting rid of makeCallback since we use templated         |
     |                 constructors now.                                          |
     |                 Making the call of an empty callback a little more safe    |
     |                 by throwing an exception CallbackEmptyCall.                |
     |                 Getting rid of operator bool and renaming isEmpty to empty.|
     |                 And some other stuff too.  Thank you Dirk Gerrits!         |
     |                 Soit, we have now officially reached version 2.00!         |
     |                                                                            |
     | I want to thank Altair, Jaap Suter & especially Dirk Gerrits (Who has      |
     | spent an entire afternoon on this to help me.  It was a waste of time for  |
     | both of us, but we had a lot of fun, didn't we? :)                         |
     *----------------------------------------------------------------------------*/

    // HOW TO USE THIS:
    //
    // 1. You create a CallbackR0 by using a ... constructor.  Surprise, surprise!
    //    It used to be done by maker functions, but we have now templated
    //    constructors.  Very cool:
    //          int foo(int a);
    //          CallbackR1<int, int> callback1(foo);
    //
    //          class Bar
    //          {
    //          public:
    //              int fun(int a);
    //          }
    //          Bar bar;
    //          CallbackR0<int, int> callback2(bar, Bar::fun);
    //
    // 2. You can copy callback objects as much as you like.
    //          CallbackR0<int, int> callback3(callback1);
    //
    //          CallbackR0<int, int> callback4;
    //          callback4 = callback2;
    //
    // 3. To excecute the callback, you evoke the function operator
    //          int r = callback1(999);
    //
    // Note: Although you can allocate callbacks without specifying the exact
    //       callback function, you must make sure the callback can do something
    //       when you excecute it.  So, you must feed it with appropriate beef
    //       (functions, object/method pair).  If you don't, funny things will
    //       happen.  A crash for example.  Luckely for you, a special exception
    //       BDG::CallbackEmptyCall will be thrown so that you can catch it.
    //       On the other hand, you could also have checked this before the call
    //       with the method empty().
    //          try
    //          {
    //              int r = callback1(999);
    //          }
    //          catch (CallbackEmptyCall)
    //          {
    //              ...
    //          }
    //
    //          if (!callback1.empty(999))
    //          {
    //              int r = callback1();
    //          }
    //
    // Note: If you use a object/method pair as callback, you must make sure the
    //       object is alive when calling the callback.  Otherwise the callback
    //       will want to do the method on dead beef, and you know funny things
    //       happen when it does that.  And you know what that means, don't you?

    #ifndef BDG_GUARDIAN_OF_INCLUSION_CALLBACKR1_H
    #define BDG_GUARDIAN_OF_INCLUSION_CALLBACKR1_H

    // --- OLD INTERFACES ----------------------------------------------------------

    #include "CallbackR1Detail.h"
    #include "CallbackExceptions.h"
    #include <algorithm>                    // std::swap

    // --- NEW INTERFACES ----------------------------------------------------------

    namespace BDG
    {

    // THE CALLBACK:
    // This is the actuall class you use to hold callbacks:

    template <typename R, typename P1>
    class CallbackR1
    {
    public:

        // CONSTRUCTORS & DESTRUCTORS

        CallbackR1():
            m_dispatcher(0)
        {
        }

        template <typename FR, typename FP1>
        explicit CallbackR1(FR (*a_function)(FP1))
        {
            if (!a_function) throw CallbackNullArgument(
                "BDG::CallbackR1: tried to construct from null function pointer.");
            using namespace CallbackR1_Detail;
            m_dispatcher = new DispFunction<R, P1, FR, FP1>(a_function);
        }

        template<class Object, typename MR, typename MP1>
        CallbackR1(Object* a_object, MR (Object::*a_method)(MP1))
        {
            if (!(a_object && a_method)) throw CallbackNullArgument(
                "BDG::CallbackR1: tried to construct from null object or method "
                "pointer.");
            using namespace CallbackR1_Detail;
            m_dispatcher = new DispMethod<Object, R, P1, MR, MP1>(a_object,
                                                                  a_method);
        }

        template<class Object, typename MR, typename MP1>
        CallbackR1(Object* a_object, MR (Object::*a_method)(MP1) const)
        {
            if (!(a_object && a_method)) throw CallbackNullArgument(
                "BDG::CallbackR1: tried to construct from null object or method "
                "pointer.");
            using namespace CallbackR1_Detail;
            m_dispatcher = new DispMethodConst<Object, R, P1, MR, MP1>(a_object,
                                                                       a_method);
        }

        CallbackR1(const CallbackR1<R, P1>& a_other):
            m_dispatcher(a_other.empty() ? 0 : a_other.m_dispatcher->clone())
        {
        }

        // OPERATORS

        CallbackR1 operator=(const CallbackR1<R, P1>& a_other)
        {
            CallbackR1<R, P1> temp(a_other);
            swap(temp);
            return *this;
        }

        R operator()(P1 a_p1) const
        {
            if (empty()) throw CallbackEmptyCall(
                "BDG::CallbackR1: tried to call an empty callback.");
            return (*m_dispatcher)(a_p1);
        }

        // METHODS

        bool empty() const
        {
            return m_dispatcher == 0;
        }

        void swap(CallbackR1<R, P1>& a_other)
        {
            std::swap(m_dispatcher, a_other.m_dispatcher);
        }

    private:

        CallbackR1_Detail::DispBase<R, P1>* m_dispatcher;
    };

    } // namespace BDG

    #endif // Guardian of Inclusion

    // --- END OF FILE CallbackR1.h ------------------------------------------------

Currently browsing [callback.zip] (32,820 bytes) - [CallbackR1Detail.h] - (6,090 bytes)

    /*----------------------------------------------------------------------------*
     | Headerfile CallbackR1Detail.h                                              |
     |                                                                            |
     | Version 2.00                                                               |
     |                                                                            |
     |                                                                            |
     | BriDGe::Callback: a tiny library that provides callback functionality.     |
     | Copyright (C) 2002  Bram de Greve                                          |
     |                                                                            |
     | This library is free software; you can redistribute it and/or              |
     | modify it under the terms of the GNU Lesser General Public                 |
     | License as published by the Free Software Foundation; either               |
     | version 2.1 of the License, or (at your option) any later version.         |
     |                                                                            |
     | This library is distributed in the hope that it will be useful,            |
     | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
     | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
     | Lesser General Public License for more details.                            |
     |                                                                            |
     | You should have received a copy of the GNU Lesser General Public           |
     | License along with this library; if not, write to the Free Software        |
     | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
     |                                                                            |
     |                                                                            |
     | Contact by e-mail: Bram de Greve <bdegreve@mail.be>                        |
     |                                                                            |
     |                                                                            |
     | History:                                                                   |
     | June 7th, 2002: Splitting CallbackR1 to multiple files.                    |
     |                 Creation of CallbackR1Detail.h                             |
     | June 8th, 2002: Revamping the code.                                        |
     |                 Putting stuff under GNU LGPL.                              |
     | June 9th, 2002: Getting rid of boost::shared_ptr so we look less silly,    |
     |                 Getting rid of makeCallback since we use templated         |
     |                 constructors now.                                          |
     |                 Making the call of an empty callback a little more safe    |
     |                 by throwing an exception CallbackEmptyCall.                |
     |                 Getting rid of operator bool and renaming isEmpty to empty.|
     |                 And some other stuff too.  Thank you Dirk Gerrits!         |
     |                 Soit, we have now officially reached version 2.00!         |
     |                                                                            |
     | I want to thank Altair, Jaap Suter & especially Dirk Gerrits (Who has      |
     | spent an entire afternoon on this to help me.  It was a waste of time for  |
     | both of us, but we had a lot of fun, didn't we? :)                         |
     *----------------------------------------------------------------------------*/

    #ifndef BDG_GUARDIAN_OF_INCLUSION_CALLBACKR1DETAIL_H
    #define BDG_GUARDIAN_OF_INCLUSION_CALLBACKR1DETAIL_H

    // --- NEW INTERFACES ----------------------------------------------------------

    namespace BDG
    {

    namespace CallbackR1_Detail
    {

    // Base class for dispatchers:

    template<typename R, typename P1>
    class DispBase
    {
    public:

        virtual R operator()(P1 a_p1) const = 0;
        virtual DispBase<R, P1>* clone() const = 0;
    };

    // Dispatcher to a non-member function:

    template<typename R, typename P1, typename FR, typename FP1>
    class DispFunction: public DispBase<R, P1>
    {
    private:

        typedef FR (*Function) (FP1);
        Function m_function;

    public:

        DispFunction(Function a_function):
            m_function(a_function)
        {
        }

        R operator()(P1 a_p1) const
        {
            return (*m_function)(a_p1);
        }

        DispBase<R, P1>* clone() const
        {
            return new DispFunction<R, P1, FR, FP1>(*this);
        }
    };

    // Dispatcher to Object/Method pair:

    template <class Object, typename R, typename P1, typename MR, typename MP1>
    class DispMethod: public DispBase<R, P1>
    {
    private:

        typedef MR (Object::*Method) (MP1);
        Object* m_object;
        Method m_method;

    public:

        DispMethod(Object* a_object, Method a_method):
            m_object(a_object),
            m_method(a_method)
        {
        }

        R operator()(P1 a_p1) const
        {
            return (m_object->*m_method)(a_p1);
        }

        DispBase<R, P1>* clone() const
        {
            return new DispMethod<Object, R, P1, MR, MP1>(*this);
        }
    };

    // Dispatcher to an object/(const method) pair:

    template <class Object, typename R, typename P1, typename MR, typename MP1>
    class DispMethodConst: public DispBase<R, P1>
    {
    private:

        typedef MR (Object::*Method) (MP1) const;
        Object* m_object;
        Method m_method;

    public:

        DispMethodConst(Object* a_object, Method a_method):
            m_object(a_object),
            m_method(a_method)
        {
        }

        R operator()(P1 a_p1) const
        {
            return (m_object->*m_method)(a_p1);
        }

        DispBase<R, P1>* clone() const
        {
            return new DispMethodConst<Object, R, P1, MR, MP1>(*this);
        }
    };

    } // namespace CallbackR1_Detail

    } // namespace BDG

    #endif // Guardian of Inclusion

    // --- END OF FILE CallbackR1Detail.h ------------------------------------------

Currently browsing [callback.zip] (32,820 bytes) - [Test.cpp] - (8,146 bytes)

    /*----------------------------------------------------------------------------*
     | Sourcefile Test.h                                                          |
     |                                                                            |
     | Version 2.00                                                               |
     |                                                                            |
     | Description:                                                               |
     |      Just a crappy test program to test the callbacks.                     |
     |                                                                            |
     |                                                                            |
     | This file is part of the the Bramz::BriDGe library.  The Bramz::BriDGe     |
     | library is about stuff that is developed for my own purpose, for having a  |
     | solid code base for my software.  However this stuff might get distributed |
     | somehow and used in other places than I originally intented.               |
     | Which is nice ...                                                          |
     |                                                                            |
     |                                                                            |
     | Copyright (C) 2002 Bram de Greve                                           |
     |                                                                            |
     |                                                                            |
     | This file is free software; you can redistribute it and/or modify          |
     | it under the terms of the GNU General Public License as published by       |
     | the Free Software Foundation; either version 2 of the License, or          |
     | (at your option) any later version.                                        |
     |                                                                            |
     | This file is distributed in the hope that it will be useful,               |
     | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
     | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              |
     | GNU General Public License for more details.                               |
     |                                                                            |
     | You should have received a copy of the GNU General Public License          |
     | along with this file; if not, write to the Free Software                   |
     | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
     |                                                                            |
     |                                                                            |
     | Contact by e-mail: Bram de Greve <bdegreve@mail.be>                        |
     |                                                                            |
     |                                                                            |
     | History:                                                                   |
     | June 7th, 2002: creation of Test.cpp                                       |
     | June 9th, 2002: Updating to test the BriDGe::Callback library 2.00         |
     |                                                                            |
     | I want to thank Altair, Jaap Suter & especially Dirk Gerrits (Who has      |
     | spent an entire afternoon on this to help me.  It was a waste of time for  |
     | both of us, but we had a lot of fun, didn't we? :)                         |
     *----------------------------------------------------------------------------*/

    #include "Callback0.h"
    #include "Callback1.h"
    #include "CallbackR0.h"
    #include "CallbackR1.h"

    #include <string>
    #include <iostream>

    // for once, we'll take shortcuts
    using namespace BDG;
    using namespace std;

    // --- TEST MATERIAL -----------------------------------------------------------

    class Dog
    {
    public:
        Dog(const string& a_name, int a_age, int a_pos): m_name(a_name), m_age(a_age), m_pos(a_pos) {}

        // 0
        void birthday() { ++m_age; cout << m_name << " is " << m_age << " now." << endl; }
        void bark() const { cout << m_name << ": Whoof!\n"; }

        // R0
        int goCrazy() { m_pos = rand(); return m_pos; }
        int getAge() const { return m_age; }

        // 1
        void setAge(int a_age) { m_age = a_age; cout << "m_age: " << m_age << endl; }
        void jump(int a_height) const { cout << "Jump " << a_height << " feet high.\n"; }

        // R1
        int run(int a_distance) { m_pos += a_distance; return m_pos; }
        bool call(const string& a_name) const { return m_name == a_name; }

    private:
        string m_name;
        int m_pos;
        int m_age;
    };

    void foo0() { cout << "foo0.\n"; }
    void foo1(int a_i) { cout << "foo1: " << a_i << endl; }
    int fooR0() { return 999; }
    bool fooR1(const string& a_s) { return a_s.empty(); }

    // --- THE TEST CHAMBER --------------------------------------------------------

    int main()
    {
        Dog eddy("Eddy", 2, 100);
        Dog freddy("Freddy", 3, 1000);

        // CALLBACK0

        Callback0 cb1;
        Callback0 cb2(&eddy, Dog::birthday);
        Callback0 cb3(&freddy, Dog::bark);

        if (!cb1.empty())
        {
            cb1();
        }
        else
        {
            cout << "Saved by the bell!\n";
        }

        try
        {
            cb1();
        }
        catch (CallbackEmptyCall emptyCall)
        {
            cout << emptyCall.what() << endl;
        }

        cb2();
        cb3();
        Callback0 cb4(cb2);
        cb4();
        cb1.swap(cb3);
        cb1();
        cb1 = Callback0(foo0);
        cb1();

        cout << endl;

        // CALLBACKR0

        CallbackR0<int> cb5;
        CallbackR0<int> cb6(&eddy, Dog::goCrazy);
        CallbackR0<int> cb7(&freddy, Dog::getAge);

        if (!cb5.empty())
        {
            cb5();
        }
        else
        {
            cout << "Saved by the bell!\n";
        }

        try
        {
            cb5();
        }
        catch (CallbackEmptyCall emptyCall)
        {
            cout << emptyCall.what() << endl;
        }

        cout << "Eddy is now at: " << cb6() << endl;
        cout << "Freddy is now " << cb7() << " years old.\n";
        CallbackR0<int> cb8(cb6);
        cout << "Eddy goes crazy again: " << cb8() << endl;
        cb5.swap(cb7);
        cout << "Age of Freddy again: " << cb5() << endl;
        cb5 = CallbackR0<int>(fooR0);
        cout << "Number: " << cb5() << endl;

        cout << endl;
        char cont;
        cout << "Press enter to test the rest ...";
        cin.get(cont);
        cout << endl;

        // CALLBACK1

        Callback1<int> cb9;
        Callback1<int> cb10(&eddy, Dog::setAge);
        Callback1<int> cb11(&freddy, Dog::jump);

        if (!cb9.empty())
        {
            cb9(666);
        }
        else
        {
            cout << "Saved by the bell!\n";
        }

        try
        {
            cb9(666);
        }
        catch (CallbackEmptyCall emptyCall)
        {
            cout << emptyCall.what() << endl;
        }

        cb10(10);
        cb11(100);
        Callback1<int> cb12(cb10);
        cb12(20);
        cb9.swap(cb11);
        cb9(200);
        cb9 = Callback1<int>(foo1);
        cb9(9);

        cout << endl;

        // CALLBACKR1

        CallbackR1<bool, const string&> cb13;
        CallbackR1<int, int> cb14(&eddy, Dog::run);
        CallbackR1<bool, const string&> cb15(&freddy, Dog::call);

        if (!cb13.empty())
        {
            cb13("666");
        }
        else
        {
            cout << "Saved by the bell!\n";
        }

        try
        {
            cb13("666");
        }
        catch (CallbackEmptyCall emptyCall)
        {
            cout << emptyCall.what() << endl;
        }

        cout << "Eddy runs and ends at " << cb14(10) << endl;
        cout << "Freddy! " << (cb15("Freddy") ? "Whoof!" : "tumbleweed") << endl;
        CallbackR1<int, int> cb16(cb14);
        cout << "Eddy runs again: " << cb16(20) << endl;
        cb13.swap(cb15);
        cout << "Josper! " << (cb13("Josper") ? "Whoof!" : "tumbleweed") << endl;
        cb13 = CallbackR1<bool, const std::string&>(fooR1);
        cout << "Is Franske empty? " << cb13("Franske") << endl;

        return 0;
    }

    // --- END OF FILE Test.cpp ----------------------------------------------------

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.