// Copyright (C) 2005  Davis E. King (davisking@users.sourceforge.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_
#ifdef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1 = void,
        typename PARAM2 = void,
        typename PARAM3 = void,
        typename PARAM4 = void
        >
    class member_function_pointer;

// ----------------------------------------------------------------------------------------

    template <>
    class member_function_pointer<void,void,void,void>
    {
        /*!
            INITIAL VALUE
                is_set() == false

            WHAT THIS OBJECT REPRESENTS
                This object represents a member function pointer.  It is useful because
                instances of this object can be created without needing to know the type
                of object whose member function we will be calling.

                There are five template specializations of this object.  The first 
                represents a pointer to a member function taking no parameters, the
                second represents a pointer to a member function taking one parameter, 
                the third to one taking two parameters, and so on.

                You specify the parameters to your member function pointer by filling in
                the PARAM template parameters.  For example:

                    To use a pointer to a function with no parameters you would say:
                        member_function_pointer<> my_pointer;
                    To use a pointer to a function that takes a single int you would say:
                        member_function_pointer<int> my_pointer;
                    To use a pointer to a function that takes an int and then a reference
                    to a string you would say:
                        member_function_pointer<int,string&> my_pointer;

                Also note that the formal comments are only present for the first 
                template specialization.  They are all exactly the same except for the 
                number of parameters each takes in its member function pointer.
        !*/

    public:
        typedef void param1_type;
        typedef void param2_type;
        typedef void param3_type;
        typedef void param4_type;

        member_function_pointer (  
        );
        /*!
            ensures                
                - #*this is properly initialized
        !*/

        member_function_pointer(
            const member_function_pointer& item
        );
        /*!
            ensures
                - *this == item
            throws
                - std::bad_alloc
        !*/

        ~member_function_pointer (
        );
        /*!
            ensures
                - any resources associated with *this have been released
        !*/

        member_function_pointer& operator=(
            const member_function_pointer& item
        );
        /*!
            ensures
                - *this == item
            throws
                - std::bad_alloc
                  If this exception is thrown then #is_set() == false
        !*/

        bool operator == (
            const member_function_pointer& item
        ) const;
        /*!
            ensures
                - if (is_set() == false && item.is_set() == false) then
                    - returns true
                - else if (both *this and item point to the same member function
                  in the same object instance) then
                    - returns true
                - else
                    - returns false
        !*/

        bool operator != (
            const member_function_pointer& item
        ) const;
        /*!
            ensures
                - returns !(*this == item)
        !*/

        void clear(
        );
        /*!
            ensures
                - #*this has its initial value
        !*/

        bool is_set (
        ) const;
        /*!
            ensures
                - if (this->set() has been called and succeeded) then
                    - returns true
                - else
                    - returns false
        !*/

        template <
            typename T
            >
        void set (
            T& object,
            void (T::*cb)()
        );
        /*!
            requires
                - cb == a valid member function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*cb)()
            throws
                - std::bad_alloc
                  If this exception is thrown then #is_set() == false
        !*/

        template <
            typename T
            >
        void set (
            const T& object,
            void (T::*cb)()const
        );
        /*!
            requires
                - cb == a valid member function pointer for class T
            ensures
                - #is_set() == true
                - calls to this->operator() will call (object.*cb)()
            throws
                - std::bad_alloc
                  If this exception is thrown then #is_set() == false
        !*/

        operator bool (
        ) const;
        /*!
            ensures
                - returns is_set()
        !*/

        bool operator! (
        ) const;
        /*!
            ensures
                - returns !is_set()
        !*/

        void operator () (
        ) const;
        /*!
            requires
                - is_set() == true
            ensures
                - calls the member function on the object specified by the last 
                  call to this->set()
            throws
                - any exception thrown by the member function specified by
                  the previous call to this->set().
                    If any of these exceptions are thrown then the call to this 
                    function will have no effect on *this.                  
        !*/

        void swap (
            member_function_pointer& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/ 

    };    

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1
        >
    class member_function_pointer<PARAM1,void,void,void>
    {
    public:
        typedef PARAM1 param1_type;
        typedef void param2_type;
        typedef void param3_type;
        typedef void param4_type;

        member_function_pointer ();

        member_function_pointer(
            const member_function_pointer& item
        );

        ~member_function_pointer (
        );

        member_function_pointer& operator=(
            const member_function_pointer& item
        );

        bool operator == (
            const member_function_pointer& item
        ) const;

        bool operator != (
            const member_function_pointer& item
        ) const;

        void clear();

        bool is_set () const;

        template <typename T>
        void set (
            T& object,
            void (T::*cb)(PARAM1)
        );

        template <typename T>
        void set (
            const T& object,
            void (T::*cb)(PARAM1)const
        );

        operator bool (
        ) const;

        bool operator! (
        ) const;

        void operator () (
            PARAM1 param1
        ) const;

        void swap (
            member_function_pointer& item
        );

    };    

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1,
        typename PARAM2
        >
    class member_function_pointer<PARAM1,PARAM2,void,void>
    {
    public:
        typedef PARAM1 param1_type;
        typedef PARAM2 param2_type;
        typedef void param3_type;
        typedef void param4_type;

        member_function_pointer ();

        member_function_pointer(
            const member_function_pointer& item
        );

        ~member_function_pointer (
        );

        member_function_pointer& operator=(
            const member_function_pointer& item
        );

        bool operator == (
            const member_function_pointer& item
        ) const;

        bool operator != (
            const member_function_pointer& item
        ) const;

        void clear();

        bool is_set () const;

        template <typename T>
        void set (
            T& object,
            void (T::*cb)(PARAM1,PARAM2)
        );

        template <typename T>
        void set (
            const T& object,
            void (T::*cb)(PARAM1,PARAM2)const
        );

        operator bool (
        ) const;

        bool operator! (
        ) const;

        void operator () (
            PARAM1 param1,
            PARAM2 param2
        ) const;

        void swap (
            member_function_pointer& item
        );

    };    

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1,
        typename PARAM2,
        typename PARAM3
        >
    class member_function_pointer<PARAM1,PARAM2,PARAM3,void>
    {
    public:
        typedef PARAM1 param1_type;
        typedef PARAM2 param2_type;
        typedef PARAM3 param3_type;
        typedef void param4_type;

        member_function_pointer ();

        member_function_pointer(
            const member_function_pointer& item
        );

        ~member_function_pointer (
        );

        member_function_pointer& operator=(
            const member_function_pointer& item
        );

        bool operator == (
            const member_function_pointer& item
        ) const;

        bool operator != (
            const member_function_pointer& item
        ) const;

        void clear();

        bool is_set () const;

        template <typename T>
        void set (
            T& object,
            void (T::*cb)(PARAM1,PARAM2,PARAM3)
        );

        template <typename T>
        void set (
            const T& object,
            void (T::*cb)(PARAM1,PARAM2,PARAM3)const
        );

        operator bool (
        ) const;

        bool operator! (
        ) const;

        void operator () (
            PARAM1 param1,
            PARAM2 param2,
            PARAM2 param3
        ) const;

        void swap (
            member_function_pointer& item
        );

    };    

// ----------------------------------------------------------------------------------------

    template <
        typename PARAM1,
        typename PARAM2,
        typename PARAM3,
        typename PARAM4
        >
    class member_function_pointer
    {
    public:
        typedef PARAM1 param1_type;
        typedef PARAM2 param2_type;
        typedef PARAM3 param3_type;
        typedef PARAM4 param4_type;

        member_function_pointer ();

        member_function_pointer(
            const member_function_pointer& item
        );

        ~member_function_pointer (
        );

        member_function_pointer& operator=(
            const member_function_pointer& item
        );

        bool operator == (
            const member_function_pointer& item
        ) const;

        bool operator != (
            const member_function_pointer& item
        ) const;

        void clear();

        bool is_set () const;

        template <typename T>
        void set (
            T& object,
            void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4)
        );

        template <typename T>
        void set (
            const T& object,
            void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4)const
        );

        operator bool (
        ) const;

        bool operator! (
        ) const;

        void operator () (
            PARAM1 param1,
            PARAM2 param2,
            PARAM2 param3,
            PARAM2 param4
        ) const;

        void swap (
            member_function_pointer& item
        );

    };    

// ----------------------------------------------------------------------------------------


}

#endif // DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_

