/*
 *   ORXONOX - the hottest 3D action shooter ever to exist
 *                    > www.orxonox.net <
 *
 *
 *   License notice:
 *
 *   This program 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 program 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 program; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 *   Author:
 *      Fabian 'x3n' Landau
 *   Co-authors:
 *      ...
 *
 */

/**
    @file
    @ingroup Command FunctorExecutor
    @brief Definition of orxonox::Functor and its specialized subclasses, as well as the createFunctor() functions.

    @anchor FunctorExample

    Functors can be used to wrap function-pointers. While function-pointers have a very
    complicated syntax in C++, Functors are always the same and you can call the wrapped
    function-pointer independently of its parameter with arguments of type MultiType. These
    arguments are then automatically converted to the right type.

    To create a Functor, the helper function createFunctor() is used. It returns an instance
    of orxonox::FunctorPtr which is simply a typedef of "std::shared_ptr<Functor>". This
    means you don't have to delete the Functor after using it, because it is managed
    by the std::shared_ptr.

    Example:
    @code
    int myStaticFunction(int value)                         // Definition of a static function
    {
        return (value * 2);                                 // Return the double of the value
    }

    FunctorPtr functor = createFunctor(&myStaticFunction);  // Create a Functor

    int result = (*functor)(5);                             // Calls the functor with value = 5, result == 10

    int result = (*functor)("7");                           // Calls the functor with a string which is converted to an integer, result == 14
    @endcode

    Functors can also be used if you work with member-functions. In this case createFunctor()
    returns an instance of orxonox::FunctorMemberPtr - this allows you to define the object
    that will be used to call the function.

    Example:
    @code
    class MyClass                                                   // Define a class
    {
        public:
            MyClass(const std::string& text)                        // Constructor
            {
                this->text_ = text;
            }

            bool contains(const std::string& word)                  // Function that searches for "word" in "text"
            {
                return (this->text_.find(word) != std::string::npos);
            }

        private:
            std::string text_;                                      // Member variable
    };

    MyClass* object = new MyClass("Hello World");                   // Create an object of type MyClass and set its text to "Hello World"

    FunctorPtr functor = createFunctor(&MyClass:contains, object);  // Create a Functor (note the object!)

    bool result = (*functor)("World");                              // result == true
    bool result = (*functor)("test");                               // result == false
    @endcode

    Instead of assigning the object directly to the functor when creating it, you can also define
    it at any later point or when you call the functor. Note however that this works only with
    orxonox::FunctorMember.

    @code
    MyClass* object1 = new MyClass("Hello World");                  // Create an object
    MyClass* object2 = new MyClass("this is a test");               // Create another object

    FunctorMemberPtr functor = createFunctor(&MyClass:contains);    // Create a FunctorMember (note: no object this time)

    bool result = (*functor)("World");                              // result == false and an error: "Error: Can't execute FunctorMember, no object set."

    bool result = (*functor)(object1, "World");                     // result == true
    bool result = (*functor)(object1, "test");                      // result == false
    bool result = (*functor)(object2, "test");                      // result == true

    functor->setObject(object1);                                    // Assign an object to the FunctorMember

    bool result = (*functor)("World");                              // result == true (no error this time, because the object was set using setObject())
    @endcode
*/

#ifndef _Functor_H__
#define _Functor_H__

#include "core/CorePrereqs.h"

#include <typeinfo>

#include "util/Output.h"
#include "util/MultiType.h"
#include "core/object/Destroyable.h"
#include "FunctorPtr.h"

namespace orxonox
{
    const unsigned int MAX_FUNCTOR_ARGUMENTS = 5;   ///< The maximum number of parameters of a function that is supported by Functor

    namespace detail
    {
        template <class T>
        inline std::string _typeToString() { return "unknown"; }

        template <> inline std::string _typeToString<void>()               { return "void"; }
        template <> inline std::string _typeToString<int>()                { return "int"; }
        template <> inline std::string _typeToString<unsigned int>()       { return "uint"; }
        template <> inline std::string _typeToString<char>()               { return "char"; }
        template <> inline std::string _typeToString<unsigned char>()      { return "uchar"; }
        template <> inline std::string _typeToString<short>()              { return "short"; }
        template <> inline std::string _typeToString<unsigned short>()     { return "ushort"; }
        template <> inline std::string _typeToString<long>()               { return "long"; }
        template <> inline std::string _typeToString<unsigned long>()      { return "ulong"; }
        template <> inline std::string _typeToString<long long>()          { return "longlong"; }
        template <> inline std::string _typeToString<unsigned long long>() { return "ulonglong"; }
        template <> inline std::string _typeToString<float>()              { return "float"; }
        template <> inline std::string _typeToString<double>()             { return "double"; }
        template <> inline std::string _typeToString<long double>()        { return "longdouble"; }
        template <> inline std::string _typeToString<bool>()               { return "bool"; }
        template <> inline std::string _typeToString<std::string>()        { return "string"; }
        template <> inline std::string _typeToString<Vector2>()            { return "Vector2"; }
        template <> inline std::string _typeToString<Vector3>()            { return "Vector3"; }
        template <> inline std::string _typeToString<Quaternion>()         { return "Quaternion"; }
        template <> inline std::string _typeToString<ColourValue>()        { return "ColourValue"; }
        template <> inline std::string _typeToString<Radian>()             { return "Radian"; }
        template <> inline std::string _typeToString<Degree>()             { return "Degree"; }
    }

    /// Returns the name of type @a T as string.
    template <class T>
    inline std::string typeToString() { return detail::_typeToString<typename Loki::TypeTraits<T>::UnqualifiedReferredType>(); }

    /**
        @brief The Functor classes are used to wrap function pointers.

        Function-pointers in C++ have a pretty complicated syntax and you can't store
        and call them unless you know the exact type. A Functor can be used to wrap
        a function-pointer and to store it independent of its type. You can also call
        it independently of its parameters by passing the arguments as MultiType. They
        are converted automatically to the right type.

        Functor is a pure virtual base class.

        @see See @ref FunctorExample "Functor.h" for some examples.
    */
    class _CoreExport Functor
    {
        public:
            /// Defines the type of a function (static or member)
            enum class Type
            {
                Static,
                Member
            };

        public:
            virtual ~Functor() = default;

            /// Calls the function-pointer with up to five arguments. In case of a member-function, the assigned object-pointer is used to call the function. @return Returns the return-value of the function (if any; MultiType::Null otherwise)
            virtual MultiType operator()(const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null) = 0;

            /// Creates a new instance of Functor with the same values like this (used instead of a copy-constructor)
            virtual FunctorPtr clone() = 0;

            /// Returns the type of the function: static or member.
            virtual Type getType() const = 0;
            /// Returns the number of parameters of the function.
            virtual unsigned int getParamCount() const = 0;
            /// Returns true if the function has a return-value.
            virtual bool hasReturnvalue() const = 0;

            /// Returns the type-name of the parameter with given index (the first parameter has index 0).
            virtual std::string getTypenameParam(unsigned int index) const = 0;
            /// Returns the type-name of the return-value.
            virtual std::string getTypenameReturnvalue() const = 0;

            /// Converts a given argument to the type of the parameter with given index (the first parameter has index 0).
            virtual void evaluateArgument(unsigned int index, MultiType& argument) const = 0;

            /// Assigns an object-pointer to the functor which is used to execute a member-function.
            virtual void setRawObjectPointer(void* object) = 0;
            /// Returns the object-pointer.
            virtual void* getRawObjectPointer() const = 0;

            /// Enables or disables the safe mode which causes the functor to change the object pointer to nullptr if the object is deleted (only member functors).
            virtual void setSafeMode(bool bSafeMode) = 0;

            /// Returns the full identifier of the function-pointer which is defined as typeid(@a F), where @a F is the type of the stored function-pointer. Used to compare functors.
            virtual const std::type_info& getFullIdentifier() const = 0;
            /// Returns an identifier of the header of the function (doesn't include the function's class). Used to compare functors.
            virtual const std::type_info& getHeaderIdentifier() const = 0;
            /// Returns an identifier of the header of the function (doesn't include the function's class), but regards only the first @a params parameters. Used to compare functions if an Executor provides default-values for the other parameters.
            virtual const std::type_info& getHeaderIdentifier(unsigned int params) const = 0;
    };

    /**
        @brief FunctorMember is a child class of Functor and expands it with an object-pointer, that
        is used for member-functions, as well as an overloaded execution operator.

        @param O The type of the function's class (or void if it's a static function)

        Note that FunctorMember is also used for static functions, but with T = void. FunctorStatic
        is a typedef of FunctorMember<void>. The void* object-pointer is ignored in this case.

        @see See @ref FunctorExample "Functor.h" for some examples.
    */
    template <class O>
    class FunctorMember : public Functor, public DestructionListener
    {
        public:
            /// Constructor: Stores the object-pointer.
            FunctorMember(O* object = nullptr) : object_(object), bSafeMode_(false) {}
            virtual ~FunctorMember() { if (this->bSafeMode_) { this->unregisterObject(this->object_); } }

            /// Calls the function-pointer with up to five arguments and an object. In case of a static-function, the object can be nullptr. @return Returns the return-value of the function (if any; MultiType::Null otherwise)
            virtual MultiType operator()(O* object, const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null) = 0;

            // see Functor::operator()()
            virtual MultiType operator()(const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null) override
            {
                // call the function if an object was assigned
                if (this->object_)
                    return (*this)(this->object_, param1, param2, param3, param4, param5);
                else
                {
                    orxout(internal_error) << "Can't execute FunctorMember, no object set." << endl;
                    return MultiType::Null;
                }
            }

            // see Functor::getType()
            virtual inline Functor::Type getType() const override
                { return Functor::Type::Member; }

            /// Assigns an object-pointer to the functor which is used to execute a member-function.
            inline void setObject(O* object)
            {
                if (this->bSafeMode_ && object != this->object_)
                {
                    this->unregisterObject(this->object_);
                    this->registerObject(object);
                }
                this->object_ = object;
            }
            /// Returns the object-pointer.
            inline O* getObject() const
                { return this->object_; }

            // see Functor::setRawObjectPointer()
            virtual inline void setRawObjectPointer(void* object) override
                { this->setObject((O*)object); }
            // see Functor::getRawObjectPointer()
            virtual inline void* getRawObjectPointer() const override
                { return this->object_; }

            // see Functor::setSafeMode()
            virtual inline void setSafeMode(bool bSafeMode) override
            {
                if (bSafeMode == this->bSafeMode_)
                    return;

                this->bSafeMode_ = bSafeMode;

                if (bSafeMode)
                    this->registerObject(this->object_);
                else
                    this->unregisterObject(this->object_);
            }

        protected:
            /// Casts the object and registers as destruction listener if the object is a Destroyable.
            inline void registerObject(Destroyable* object)
                { this->registerAsDestructionListener(object); }

            inline void registerObject(void* object) {}

            /// Casts the object and unregisters as destruction listener if the object is a Destroyable.
            inline void unregisterObject(Destroyable* object)
                { this->unregisterAsDestructionListener(object); }

            inline void unregisterObject(void* object) {}

            /// Will be called by Destroyable::~Destroyable() if the stored object is a Destroyable and deleted and the Functor is in safe mode.
            virtual inline void objectDeleted() override
                { this->object_ = nullptr; }

            O* object_;     ///< The stored object-pointer, used to execute a member-function (or nullptr for static functions)
            bool bSafeMode_; ///< If true, the functor is in safe mode and registers itself as listener at the object and changes the pointer to nullptr if the object is deleted
    };

    /// Specialization of FunctorMember with @a T = void.
    template <>
    class FunctorMember<void> : public Functor
    {
        public:
            /// Constructor: Stores the object-pointer.
            FunctorMember(void* object = nullptr) {}

            /// Calls the function-pointer with up to five arguments and an object. In case of a static-function, the object can be nullptr. @return Returns the return-value of the function (if any; MultiType::Null otherwise)
            virtual MultiType operator()(void* object, const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null) = 0;

            // see Functor::operator()()
            virtual MultiType operator()(const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null) override
            {
                return (*this)((void*)nullptr, param1, param2, param3, param4, param5);
            }

            // see Functor::getType()
            virtual inline Functor::Type getType() const override
                { return Functor::Type::Static; }

            // see Functor::setRawObjectPointer()
            virtual inline void setRawObjectPointer(void*) override
                { orxout(internal_warning) << "Can't assign an object pointer to a static functor" << endl; }
            // see Functor::getRawObjectPointer()
            virtual inline void* getRawObjectPointer() const override
                { return nullptr; }

            // see Functor::setSafeMode()
            virtual inline void setSafeMode(bool) override {}
    };

    /// FunctorStatic is just a typedef of FunctorMember with @a T = void.
    typedef FunctorMember<void> FunctorStatic;

    /**
        @brief FunctorPointer is a child class of FunctorMember and extends it with a function-pointer (or a function-object).
        @param F The type of the function-pointer (or the function-object)
        @param O The type of the function's class (or void if it's a static function or a function-object)

        The template FunctorPointer has an additional template parameter that defines the type
        of the function-pointer (or the function-object). This can be handy if you want to get
        or set the function-pointer (or the function-object). You can then use a static_cast
        to cast a Functor to FunctorPointer if you know the type of the function.

        However FunctorPointer is not aware of the types of the different parameters or the
        return value.
    */
    template <class F, class O = void>
    class FunctorPointer : public FunctorMember<O>
    {
        public:
            /// Constructor: Initializes the base class and stores the function-pointer.
            FunctorPointer(F functionPointer, O* object = nullptr) : FunctorMember<O>(object), functionPointer_(functionPointer) {}

            /// Changes the function-pointer.
            inline void setFunction(F functionPointer)
                { this->functionPointer_ = functionPointer; }
            /// Returns the function-pointer.
            inline F getFunction() const
                { return this->functionPointer_; }

        protected:
            F functionPointer_;     ///< The stored function-pointer
    };

    namespace detail
    {
        // Helper class to get the type of the function-pointer (or the function-object) with the given class, parameters, return-value, and constness
        template <class F, class R, class O, bool isconst, class... Params> struct FunctionType /* generic type is undefined */;
        template <         class R, class O,               class... Params> struct FunctionType<void, R, O,    false, Params...> { typedef R (O::*Type)(Params...); };       // spezialization: non-const member function
        template <         class R, class O,               class... Params> struct FunctionType<void, R, O,    true,  Params...> { typedef R (O::*Type)(Params...) const; }; // spezialization: const member function
        template <         class R,                        class... Params> struct FunctionType<void, R, void, false, Params...> { typedef R (*Type)(Params...); };          // spezialization: static function
        template <class F, class R,                        class... Params> struct FunctionType<F,    R, void, false, Params...> { typedef F Type; };                        // spezialization: function object

        // Helper class, used to call a function with a given object and parameters and to return its return-value (if available)
        template <class F, class R, class O, bool isconst, class... Params> struct FunctorCaller /* generic type is undefined */;
        template <         class R, class O, bool isconst, class... Params> struct FunctorCaller<void, R,    O,    isconst, Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<void, R,    O,    isconst, Params...>::Type functionPointer, O* object, const Params&... parameters, const UnusedParams&...) { return (object->*functionPointer)(parameters...); } };                  // spezialization: member function with return value
        template <                  class O, bool isconst, class... Params> struct FunctorCaller<void, void, O,    isconst, Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<void, void, O,    isconst, Params...>::Type functionPointer, O* object, const Params&... parameters, const UnusedParams&...) { (object->*functionPointer)(parameters...); return MultiType::Null; } }; // spezialization: member function without return value
        template <         class R,                        class... Params> struct FunctorCaller<void, R,    void, false,   Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<void, R,    void, false,   Params...>::Type functionPointer, void*,     const Params&... parameters, const UnusedParams&...) { return (*functionPointer)(parameters...); } };                          // spezialization: static function with return value
        template <                                         class... Params> struct FunctorCaller<void, void, void, false,   Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<void, void, void, false,   Params...>::Type functionPointer, void*,     const Params&... parameters, const UnusedParams&...) { (*functionPointer)(parameters...); return MultiType::Null; } };         // spezialization: static function without return value
        template <class F, class R,                        class... Params> struct FunctorCaller<F,    R,    void, false,   Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<F,    R,    void, false,   Params...>::Type functor,         void*,     const Params&... parameters, const UnusedParams&...) { return functor(parameters...); } };                                     // spezialization: function object with return value
        template <class F,                                 class... Params> struct FunctorCaller<F,    void, void, false,   Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<F,    void, void, false,   Params...>::Type functor,         void*,     const Params&... parameters, const UnusedParams&...) { functor(parameters...); return MultiType::Null; } };                    // spezialization: function object without return value

        // Helper class to determine if a function has a returnvalue
        template <class T>
        struct FunctorHasReturnvalue
        { enum { result = true }; };
        template <>
        struct FunctorHasReturnvalue<void>
        { enum { result = false }; };

        // Helper class to determine the N-th parameter of a variadic template (with 0 being the index of the first parameter)
        template <int n, typename T = void, typename... Other>
        struct GetNthParamType
        { typedef typename GetNthParamType<n - 1, Other...>::Type Type; };
        template <typename T, typename... Other>
        struct GetNthParamType<0, T, Other...>
        { typedef T Type; };

        // Helper structs to deduce the first N types of a parameter pack
        template<class... Types> struct type_list {};

        template <class T1, class... AllTypes>
        struct make_type_list_helper
        {
            template <std::size_t N, class... Types>
            struct make_type_list_impl : make_type_list_helper<AllTypes...>::template make_type_list_impl<N - 1, Types..., T1> {};

            template <class... Types>
            struct make_type_list_impl<1u, Types...> : type_list<Types..., T1> {};
        };

        template <class T1>
        struct make_type_list_helper<T1>
        {
            template <std::size_t N, class... Types>
            struct make_type_list_impl : type_list<Types..., T1> {};
        };

        template <std::size_t N, class... Types>
        struct make_type_list : make_type_list_helper<Types...>::template make_type_list_impl<N> {};

        template <class... Types>
        struct make_type_list<0u, Types...> : type_list<> {};

        template <std::size_t N>
        struct make_type_list<N> : type_list<> {};

        template <>
        struct make_type_list<0u> : type_list<> {};
    }

    /**
        @brief FunctorTemplate is a child class of FunctorPointer and implements all functions
        that need to know the exact types of the parameters, return-value, and class.

        @param F the type of the function-object (or void if a function-pointer is used).
        @param R The type of the return-value of the function
        @param O The class of the function
        @param isconst True if the function is a const member-function
        @param Params The types of the parameters

        This template has many parameters and is usually not used directly. It is created by
        createFunctor(), but only the base-classes Functor, FunctorMember, and FunctorPointer
        are used directly. It implements all the virtual functions that are declared by its
        base classes.

        All template arguments can be void.
    */
    template <class F, class R, class O, bool isconst, class... Params>
    class FunctorTemplate : public FunctorPointer<typename detail::FunctionType<F, R, O, isconst, Params...>::Type, O>
    {
        static_assert(sizeof...(Params) <= 5, "Only up to 5 parameters are supported");

        public:
            /// Constructor: Initializes the base class.
            FunctorTemplate(typename detail::FunctionType<F, R, O, isconst, Params...>::Type functionPointer, O* object = nullptr) : FunctorPointer<typename detail::FunctionType<F, R, O, isconst, Params...>::Type, O>(functionPointer, object) {}

            // see FunctorMember::operator()()
            virtual MultiType operator()(O* object, const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null) override
            {
                return detail::FunctorCaller<F, R, O, isconst, Params...>::call(this->functionPointer_, object, param1, param2, param3, param4, param5);
            }

            // see Functor::clone()
            virtual FunctorPtr clone() override
            {
                return std::make_shared<FunctorTemplate>(*this);
            }

            // see Functor::evaluateArgument()
            virtual void evaluateArgument(unsigned int index, MultiType& argument) const override
            {
                switch (index)
                {
                    case 0: argument.convert<typename detail::GetNthParamType<0, Params...>::Type>(); break;
                    case 1: argument.convert<typename detail::GetNthParamType<1, Params...>::Type>(); break;
                    case 2: argument.convert<typename detail::GetNthParamType<2, Params...>::Type>(); break;
                    case 3: argument.convert<typename detail::GetNthParamType<3, Params...>::Type>(); break;
                    case 4: argument.convert<typename detail::GetNthParamType<4, Params...>::Type>(); break;
                }
            }

            // see Functor::getParamCount()
            virtual unsigned int getParamCount() const override
            {
                return sizeof...(Params);
            }

            // see Functor::hasReturnvalue()
            virtual bool hasReturnvalue() const override
            {
                return detail::FunctorHasReturnvalue<R>::result;
            }

            // see Functor::getTypenameParam()
            virtual std::string getTypenameParam(unsigned int index) const override
            {
                switch (index)
                {
                    case 0:  return typeToString<typename detail::GetNthParamType<0, Params...>::Type>();
                    case 1:  return typeToString<typename detail::GetNthParamType<1, Params...>::Type>();
                    case 2:  return typeToString<typename detail::GetNthParamType<2, Params...>::Type>();
                    case 3:  return typeToString<typename detail::GetNthParamType<3, Params...>::Type>();
                    case 4:  return typeToString<typename detail::GetNthParamType<4, Params...>::Type>();
                    default: return "";
                }
            }

            // see Functor::getTypenameReturnvalue()
            virtual std::string getTypenameReturnvalue() const override
            {
                return typeToString<R>();
            }

            // see Functor::getFullIdentifier()
            virtual const std::type_info& getFullIdentifier() const override
            {
                return typeid(typename detail::FunctionType<void, R, O, isconst, Params...>::Type);
            }

            // see Functor::getHeaderIdentifier()
            virtual const std::type_info& getHeaderIdentifier() const override
            {
                return typeid(typename detail::FunctionType<void, R, void, false, Params...>::Type);
            }

            // see Functor::getHeaderIdentifier(unsigned int)
            virtual const std::type_info& getHeaderIdentifier(unsigned int params) const override
            {
                switch (params)
                {
                    case 0:  return this->getTypelistIdentifier(detail::make_type_list<0, Params...>{});
                    case 1:  return this->getTypelistIdentifier(detail::make_type_list<1, Params...>{});
                    case 2:  return this->getTypelistIdentifier(detail::make_type_list<2, Params...>{});
                    case 3:  return this->getTypelistIdentifier(detail::make_type_list<3, Params...>{});
                    case 4:  return this->getTypelistIdentifier(detail::make_type_list<4, Params...>{});
                    default: return this->getTypelistIdentifier(detail::make_type_list<5, Params...>{});
                }
            }

    private:
            /// Helper function that deduces a parameter pack of types and returns the corresponding identifier
            template<class... Types>
            const std::type_info& getTypelistIdentifier(detail::type_list<Types...>) const
            {
                return typeid(typename detail::FunctionType<void, R, void, false, Types...>::Type);
            }
    };


    namespace detail
    {
        // Helper functions to deduce types and constness of operator() and return the correct FunctorTemplate
        template <class F>
        struct CallableHelper
        {
            template <class R, class... Params> static inline FunctorStaticPtr create(const F& functionObject, R(F::*)(Params...))       { return std::make_shared<FunctorTemplate<F, R, void, false, Params...>>(functionObject); }
            template <class R, class... Params> static inline FunctorStaticPtr create(const F& functionObject, R(F::*)(Params...) const) { return std::make_shared<FunctorTemplate<F, R, void, false, Params...>>(functionObject); } // note: both const and non-const function-objects are treated as static functors with isconst=false.
        };
    }

    template <class R, class O, class OO, class... Params> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(Params...),       OO* object) { return std::make_shared<FunctorTemplate<void, R, O, false, Params...>>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object
    template <class R, class O, class OO, class... Params> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(Params...) const, OO* object) { return std::make_shared<FunctorTemplate<void, R, O, true,  Params...>>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object

    template <class R, class O, class... Params> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(Params...))       { return std::make_shared<FunctorTemplate<void, R, O, false, Params...>>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer
    template <class R, class O, class... Params> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(Params...) const) { return std::make_shared<FunctorTemplate<void, R, O, true,  Params...>>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer

    template <class R, class... Params> inline FunctorStaticPtr createFunctor(R (*functionPointer)(Params...)) { return std::make_shared<FunctorTemplate<void, R, void, false, Params...>>(functionPointer); } ///< Creates a new FunctorStatic with the given function-pointer

    /** Take care that this functor does not outlive objects that have been captured by reference in a lambda. */
    template <class F> inline FunctorStaticPtr createFunctor(const F& functionObject) { return detail::CallableHelper<F>::create(functionObject, &F::operator()); } ///< Creates a new Functor with a callable object
}

#endif /* _Functor_H__ */
