    // Copyright (C) 2011  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #undef DLIB_AnY_FUNCTION_ABSTRACT_H_
    #ifdef DLIB_AnY_FUNCTION_ABSTRACT_H_

    #include "any_abstract.h"
    #include "../algs.h"

    namespace dlib
    {

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

        template <
            typename function_type
            >
        class any_function
        {
            /*!
                REQUIREMENTS ON function_type
                    This type should be a function signature.  Some examples are:
                        void (int,int)  // a function returning nothing and taking two ints
                        void ()         // a function returning nothing and taking no arguments
                        char (double&)  // a function returning a char and taking a reference to a double

                    The number of arguments in the function must be no greater than 10.

                INITIAL VALUE
                    - is_empty() == true
                    - for all T: contains<T>() == false

                WHAT THIS OBJECT REPRESENTS
                    This object is a version of dlib::any that is restricted to containing
                    elements which are some kind of function object with an operator() which
                    matches the function signature defined by function_type.

                    Here is an example:
                        #include <iostream>
                        #include <string>
                        #include "dlib/any.h"
                        using namespace std;
                        void print_message(string str) { cout << str << endl; }

                        int main()
                        {
                            dlib::any_function<void(string)> f;
                            f = print_message;
                            f("hello world"); // calls print_message("hello world")
                        }

                    Note that any_function objects can be used to store general function
                    objects (i.e. defined by a class with an overloaded operator()) in
                    addition to regular global functions.
            !*/

        public:

            // This is the type of object returned by function_type functions.
            typedef result_type_for_function_type result_type;
            // Typedefs defining the argument types.  If an argument does not exist
            // then it is set to void.
            typedef type_of_first_argument_in_funct_type  arg1_type;
            typedef type_of_second_argument_in_funct_type arg2_type;
            ...
            typedef type_of_last_argument_in_funct_type   arg10_type;
            const static unsigned long num_args = total_number_of_non_void_arguments;

            any_function(
            );
            /*!
                ensures
                    - this object is properly initialized
            !*/

            any_function (
                const any_function& item
            );
            /*!
                ensures
                    - copies the state of item into *this.
                    - Note that *this and item will contain independent copies of the
                      contents of item.  That is, this function performs a deep
                      copy and therefore does not result in *this containing
                      any kind of reference to item.
            !*/

            template < typename T >
            any_function (
                const T& item
            );
            /*!
                ensures
                    - #contains<T>() == true
                    - #cast_to<T>() == item
                      (i.e. a copy of item will be stored in *this)
            !*/

            void clear (
            );
            /*!
                ensures
                    - #*this will have its default value.  I.e. #is_empty() == true
            !*/

            template <typename T>
            bool contains (
            ) const;
            /*!
                ensures
                    - if (this object currently contains an object of type T) then
                        - returns true
                    - else
                        - returns false
            !*/

            bool is_empty(
            ) const;
            /*!
                ensures
                    - if (this object contains any kind of object) then
                        - returns false
                    - else
                        - returns true
            !*/

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

            result_type operator() (
            ) const;
            /*!
                requires
                    - is_empty() == false
                    - the signature defined by function_type takes no arguments
                ensures
                    - Let F denote the function object contained within *this.  Then
                      this function performs:
                        return F()
                      or if result_type is void then this function performs:
                        F()
            !*/

            result_type operator() (
                const arg1_type& a1
            ) const;
            /*!
                requires
                    - is_empty() == false
                    - the signature defined by function_type takes one argument
                ensures
                    - Let F denote the function object contained within *this.  Then
                      this function performs:
                        return F(a1)
                      or if result_type is void then this function performs:
                        F(a1)
            !*/

            result_type operator() (
                const arg1_type& a1,
                const arg2_type& a2
            ) const;
            /*!
                requires
                    - is_empty() == false
                    - the signature defined by function_type takes two arguments
                ensures
                    - Let F denote the function object contained within *this.  Then
                      this function performs:
                        return F(a1,a2)
                      or if result_type is void then this function performs:
                        F(a1,a2)
            !*/

            /* !!!!!!!!!  NOTE  !!!!!!!!!

               In addition to the above, operator() is defined for up to 10 arguments.
               They are not listed here because it would clutter the documentation.

               !!!!!!!!!  NOTE  !!!!!!!!!  */

            template <typename T>
            T& cast_to(
            );
            /*!
                ensures
                    - if (contains<T>() == true) then
                        - returns a non-const reference to the object contained within *this
                    - else
                        - throws bad_any_cast
            !*/

            template <typename T>
            const T& cast_to(
            ) const;
            /*!
                ensures
                    - if (contains<T>() == true) then
                        - returns a const reference to the object contained within *this
                    - else
                        - throws bad_any_cast
            !*/

            template <typename T>
            T& get(
            );
            /*!
                ensures
                    - #is_empty() == false
                    - #contains<T>() == true
                    - if (contains<T>() == true)
                        - returns a non-const reference to the object contained in *this.
                    - else
                        - Constructs an object of type T inside *this
                        - Any previous object stored in this any_function object is destructed and its
                          state is lost.
                        - returns a non-const reference to the newly created T object.
            !*/

            any_function& operator= (
                const any_function& item
            );
            /*!
                ensures
                    - copies the state of item into *this.
                    - Note that *this and item will contain independent copies of the
                      contents of item.  That is, this function performs a deep
                      copy and therefore does not result in *this containing
                      any kind of reference to item.
            !*/

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

        };

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

        template <
            typename function_type
            >
        inline void swap (
            any_function<function_type>& a,
            any_function<function_type>& b
        ) { a.swap(b); }
        /*!
            provides a global swap function
        !*/

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

        template <
            typename T,
            typename function_type
            >
        T& any_cast(
            any_function<function_type>& a
        ) { return a.cast_to<T>(); }
        /*!
            ensures
                - returns a.cast_to<T>()
        !*/

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

        template <
            typename T,
            typename function_type
            >
        const T& any_cast(
            const any_function<function_type>& a
        ) { return a.cast_to<T>(); }
        /*!
            ensures
                - returns a.cast_to<T>()
        !*/

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

    }

    #endif // DLIB_AnY_FUNCTION_ABSTRACT_H_