Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/src/libraries/core/command/Functor.h @ 10975

Last change on this file since 10975 was 10975, checked in by muemart, 8 years ago

Extend Functor to handle any callable objects (lambdas!). Had to modify (un)registerObject, because apparently you can't dynamic_cast lambdas. Also wanted to perfect forward the object from createFunctor until obj_, but MSVC didn't like that.
Including new and improved Functor tests.

  • Property svn:eol-style set to native
File size: 32.2 KB
RevLine 
[1505]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
[7401]29/**
30    @file
31    @ingroup Command FunctorExecutor
32    @brief Definition of orxonox::Functor and its specialized subclasses, as well as the createFunctor() functions.
33
34    @anchor FunctorExample
35
36    Functors can be used to wrap function-pointers. While function-pointers have a very
37    complicated syntax in C++, Functors are always the same and you can call the wrapped
38    function-pointer independently of its parameter with arguments of type MultiType. These
39    arguments are then automatically converted to the right type.
40
41    To create a Functor, the helper function createFunctor() is used. It returns an instance
[10828]42    of orxonox::FunctorPtr which is simply a typedef of "std::shared_ptr<Functor>". This
43    means you don't have to delete the Functor after using it, because it is managed
44    by the std::shared_ptr.
[7401]45
46    Example:
47    @code
48    int myStaticFunction(int value)                         // Definition of a static function
49    {
50        return (value * 2);                                 // Return the double of the value
51    }
52
53    FunctorPtr functor = createFunctor(&myStaticFunction);  // Create a Functor
54
55    int result = (*functor)(5);                             // Calls the functor with value = 5, result == 10
56
57    int result = (*functor)("7");                           // Calls the functor with a string which is converted to an integer, result == 14
58    @endcode
59
60    Functors can also be used if you work with member-functions. In this case createFunctor()
61    returns an instance of orxonox::FunctorMemberPtr - this allows you to define the object
62    that will be used to call the function.
63
64    Example:
65    @code
66    class MyClass                                                   // Define a class
67    {
68        public:
69            MyClass(const std::string& text)                        // Constructor
70            {
71                this->text_ = text;
72            }
73
74            bool contains(const std::string& word)                  // Function that searches for "word" in "text"
75            {
76                return (this->text_.find(word) != std::string::npos);
77            }
78
79        private:
80            std::string text_;                                      // Member variable
81    };
82
83    MyClass* object = new MyClass("Hello World");                   // Create an object of type MyClass and set its text to "Hello World"
84
85    FunctorPtr functor = createFunctor(&MyClass:contains, object);  // Create a Functor (note the object!)
86
87    bool result = (*functor)("World");                              // result == true
88    bool result = (*functor)("test");                               // result == false
89    @endcode
90
91    Instead of assigning the object directly to the functor when creating it, you can also define
92    it at any later point or when you call the functor. Note however that this works only with
93    orxonox::FunctorMember.
94
95    @code
96    MyClass* object1 = new MyClass("Hello World");                  // Create an object
97    MyClass* object2 = new MyClass("this is a test");               // Create another object
98
99    FunctorMemberPtr functor = createFunctor(&MyClass:contains);    // Create a FunctorMember (note: no object this time)
100
101    bool result = (*functor)("World");                              // result == false and an error: "Error: Can't execute FunctorMember, no object set."
102
103    bool result = (*functor)(object1, "World");                     // result == true
104    bool result = (*functor)(object1, "test");                      // result == false
105    bool result = (*functor)(object2, "test");                      // result == true
106
107    functor->setObject(object1);                                    // Assign an object to the FunctorMember
108
109    bool result = (*functor)("World");                              // result == true (no error this time, because the object was set using setObject())
110    @endcode
111*/
112
[1505]113#ifndef _Functor_H__
114#define _Functor_H__
115
[8729]116#include "core/CorePrereqs.h"
117
[10876]118#include <array>
119#include <typeindex>
[10975]120#include <type_traits>
[10876]121#include <tuple>
[7179]122
[8858]123#include "util/Output.h"
[1747]124#include "util/MultiType.h"
[9667]125#include "core/object/Destroyable.h"
[7196]126#include "FunctorPtr.h"
[1505]127
128namespace orxonox
129{
[7401]130    const unsigned int MAX_FUNCTOR_ARGUMENTS = 5;   ///< The maximum number of parameters of a function that is supported by Functor
[1784]131
[7401]132    namespace detail
133    {
134        template <class T>
135        inline std::string _typeToString() { return "unknown"; }
[1505]136
[7401]137        template <> inline std::string _typeToString<void>()               { return "void"; }
138        template <> inline std::string _typeToString<int>()                { return "int"; }
139        template <> inline std::string _typeToString<unsigned int>()       { return "uint"; }
140        template <> inline std::string _typeToString<char>()               { return "char"; }
141        template <> inline std::string _typeToString<unsigned char>()      { return "uchar"; }
142        template <> inline std::string _typeToString<short>()              { return "short"; }
143        template <> inline std::string _typeToString<unsigned short>()     { return "ushort"; }
144        template <> inline std::string _typeToString<long>()               { return "long"; }
145        template <> inline std::string _typeToString<unsigned long>()      { return "ulong"; }
146        template <> inline std::string _typeToString<long long>()          { return "longlong"; }
147        template <> inline std::string _typeToString<unsigned long long>() { return "ulonglong"; }
148        template <> inline std::string _typeToString<float>()              { return "float"; }
149        template <> inline std::string _typeToString<double>()             { return "double"; }
150        template <> inline std::string _typeToString<long double>()        { return "longdouble"; }
151        template <> inline std::string _typeToString<bool>()               { return "bool"; }
152        template <> inline std::string _typeToString<std::string>()        { return "string"; }
153        template <> inline std::string _typeToString<Vector2>()            { return "Vector2"; }
154        template <> inline std::string _typeToString<Vector3>()            { return "Vector3"; }
155        template <> inline std::string _typeToString<Quaternion>()         { return "Quaternion"; }
156        template <> inline std::string _typeToString<ColourValue>()        { return "ColourValue"; }
157        template <> inline std::string _typeToString<Radian>()             { return "Radian"; }
158        template <> inline std::string _typeToString<Degree>()             { return "Degree"; }
159    }
[1505]160
[7401]161    /// Returns the name of type @a T as string.
[7212]162    template <class T>
[7401]163    inline std::string typeToString() { return detail::_typeToString<typename Loki::TypeTraits<T>::UnqualifiedReferredType>(); }
[1505]164
[7401]165    /**
166        @brief The Functor classes are used to wrap function pointers.
167
168        Function-pointers in C++ have a pretty complicated syntax and you can't store
169        and call them unless you know the exact type. A Functor can be used to wrap
170        a function-pointer and to store it independent of its type. You can also call
171        it independently of its parameters by passing the arguments as MultiType. They
172        are converted automatically to the right type.
173
174        Functor is a pure virtual base class.
175
176        @see See @ref FunctorExample "Functor.h" for some examples.
177    */
[1505]178    class _CoreExport Functor
179    {
180        public:
[7188]181            struct Type
182            {
[7401]183                /// Defines the type of a function (static or member)
[7188]184                enum Enum
185                {
186                    Static,
[7212]187                    Member
[7188]188                };
189            };
190
191        public:
[7851]192            virtual ~Functor() {}
193
[9550]194            /// 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)
195            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;
[1505]196
[7401]197            /// Creates a new instance of Functor with the same values like this (used instead of a copy-constructor)
[7270]198            virtual FunctorPtr clone() = 0;
199
[7401]200            /// Returns the type of the function: static or member.
[7188]201            virtual Type::Enum getType() const = 0;
[7401]202            /// Returns the number of parameters of the function.
[7188]203            virtual unsigned int getParamCount() const = 0;
[7401]204            /// Returns true if the function has a return-value.
[7188]205            virtual bool hasReturnvalue() const = 0;
[1505]206
[7401]207            /// Returns the type-name of the parameter with given index (the first parameter has index 0).
208            virtual std::string getTypenameParam(unsigned int index) const = 0;
209            /// Returns the type-name of the return-value.
[7188]210            virtual std::string getTypenameReturnvalue() const = 0;
211
[7401]212            /// Converts a given argument to the type of the parameter with given index (the first parameter has index 0).
213            virtual void evaluateArgument(unsigned int index, MultiType& argument) const = 0;
[1505]214
[7401]215            /// Assigns an object-pointer to the functor which is used to execute a member-function.
216            virtual void setRawObjectPointer(void* object) = 0;
217            /// Returns the object-pointer.
218            virtual void* getRawObjectPointer() const = 0;
[7179]219
[10765]220            /// 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).
[7851]221            virtual void setSafeMode(bool bSafeMode) = 0;
222
[7401]223            /// 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.
[10876]224            virtual const std::type_index getFullIdentifier() const = 0;
[7401]225            /// Returns an identifier of the header of the function (doesn't include the function's class). Used to compare functors.
[10876]226            virtual const std::type_index getHeaderIdentifier() const = 0;
[7401]227            /// 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.
[10876]228            virtual const std::type_index getHeaderIdentifier(unsigned int params) const = 0;
[1505]229    };
230
[7401]231    /**
232        @brief FunctorMember is a child class of Functor and expands it with an object-pointer, that
233        is used for member-functions, as well as an overloaded execution operator.
234
235        @param O The type of the function's class (or void if it's a static function)
236
237        Note that FunctorMember is also used for static functions, but with T = void. FunctorStatic
238        is a typedef of FunctorMember<void>. The void* object-pointer is ignored in this case.
239
240        @see See @ref FunctorExample "Functor.h" for some examples.
241    */
[7212]242    template <class O>
[7851]243    class FunctorMember : public Functor, public DestructionListener
[1505]244    {
245        public:
[7401]246            /// Constructor: Stores the object-pointer.
[10768]247            FunctorMember(O* object = nullptr) : object_(object), bSafeMode_(false) {}
[7851]248            virtual ~FunctorMember() { if (this->bSafeMode_) { this->unregisterObject(this->object_); } }
[1505]249
[10765]250            /// 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)
[9550]251            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;
[1505]252
[7401]253            // see Functor::operator()()
[10845]254            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
[1505]255            {
[7851]256                // call the function if an object was assigned
257                if (this->object_)
[7189]258                    return (*this)(this->object_, param1, param2, param3, param4, param5);
[1505]259                else
260                {
[8858]261                    orxout(internal_error) << "Can't execute FunctorMember, no object set." << endl;
[9550]262                    return MultiType::Null;
[1505]263                }
264            }
265
[7401]266            // see Functor::getType()
[10845]267            virtual inline Functor::Type::Enum getType() const override
[7851]268                { return Functor::Type::Member; }
[1505]269
[7401]270            /// Assigns an object-pointer to the functor which is used to execute a member-function.
[7212]271            inline void setObject(O* object)
[7851]272            {
273                if (this->bSafeMode_ && object != this->object_)
274                {
275                    this->unregisterObject(this->object_);
276                    this->registerObject(object);
277                }
278                this->object_ = object;
279            }
[7401]280            /// Returns the object-pointer.
[7212]281            inline O* getObject() const
282                { return this->object_; }
[1505]283
[7401]284            // see Functor::setRawObjectPointer()
[10845]285            virtual inline void setRawObjectPointer(void* object) override
[7851]286                { this->setObject((O*)object); }
[7401]287            // see Functor::getRawObjectPointer()
[10845]288            virtual inline void* getRawObjectPointer() const override
[7212]289                { return this->object_; }
[7179]290
[7851]291            // see Functor::setSafeMode()
[10845]292            virtual inline void setSafeMode(bool bSafeMode) override
[7851]293            {
294                if (bSafeMode == this->bSafeMode_)
295                    return;
296
297                this->bSafeMode_ = bSafeMode;
298
299                if (bSafeMode)
300                    this->registerObject(this->object_);
301                else
302                    this->unregisterObject(this->object_);
303            }
304
[7212]305        protected:
[10975]306            /// Casts the object and registers as destruction listener if the object is a Destroyable.
307            template<bool = std::is_base_of<Destroyable, O>::value>
[7851]308            inline void registerObject(O* object)
[10975]309                { this->registerAsDestructionListener(static_cast<Destroyable*>(object)); }
310
311            template<>
312            inline void registerObject<false>(O* object) {}
313
314            /// Casts the object and unregisters as destruction listener if the object is a Destroyable.
315            template<bool = std::is_base_of<Destroyable, O>::value>
[7851]316            inline void unregisterObject(O* object)
[10975]317                { this->unregisterAsDestructionListener(static_cast<Destroyable*>(object)); }
[7851]318
[10975]319            template<>
320            inline void unregisterObject<false>(O* object) {}
321
322            /// Will be called by Destroyable::~Destroyable() if the stored object is a Destroyable and deleted and the Functor is in safe mode.
[10845]323            virtual inline void objectDeleted() override
[10768]324                { this->object_ = nullptr; }
[7851]325
[10765]326            O* object_;     ///< The stored object-pointer, used to execute a member-function (or nullptr for static functions)
327            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
[7212]328    };
[7179]329
[7851]330    /// Specialization of FunctorMember with @a T = void.
331    template <>
332    class FunctorMember<void> : public Functor
333    {
334        public:
335            /// Constructor: Stores the object-pointer.
[10768]336            FunctorMember(void* object = nullptr) {}
[7851]337
[10765]338            /// 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)
[9550]339            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;
[7851]340
341            // see Functor::operator()()
[10845]342            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
[7851]343            {
[10768]344                return (*this)((void*)nullptr, param1, param2, param3, param4, param5);
[7851]345            }
346
347            // see Functor::getType()
[10845]348            virtual inline Functor::Type::Enum getType() const override
[7851]349                { return Functor::Type::Static; }
350
351            // see Functor::setRawObjectPointer()
[10845]352            virtual inline void setRawObjectPointer(void*) override
[8858]353                { orxout(internal_warning) << "Can't assign an object pointer to a static functor" << endl; }
[7851]354            // see Functor::getRawObjectPointer()
[10845]355            virtual inline void* getRawObjectPointer() const override
[10768]356                { return nullptr; }
[7851]357
358            // see Functor::setSafeMode()
[10845]359            virtual inline void setSafeMode(bool) override {}
[7851]360    };
361
[7401]362    /// FunctorStatic is just a typedef of FunctorMember with @a T = void.
[7212]363    typedef FunctorMember<void> FunctorStatic;
[1505]364
[7401]365    /**
366        @brief FunctorPointer is a child class of FunctorMember and expands it with a function-pointer.
367        @param F The type of the function-pointer
368        @param O The type of the function's class (or void if it's a static function)
369
370        The template FunctorPointer has an additional template parameter that defines the type
371        of the function-pointer. This can be handy if you want to get or set the function-pointer.
372        You can then use a static_cast to cast a Functor to FunctorPointer if you know the type
373        of the function-pointer.
374
375        However FunctorPointer is not aware of the types of the different parameters or the
376        return value.
377    */
[7213]378    template <class F, class O = void>
[7212]379    class FunctorPointer : public FunctorMember<O>
380    {
381        public:
[7401]382            /// Constructor: Initializes the base class and stores the function-pointer.
[10768]383            FunctorPointer(F functionPointer, O* object = nullptr) : FunctorMember<O>(object), functionPointer_(functionPointer) {}
[1505]384
[7401]385            /// Changes the function-pointer.
[7212]386            inline void setFunction(F functionPointer)
387                { this->functionPointer_ = functionPointer; }
[7401]388            /// Returns the function-pointer.
[7212]389            inline F getFunction() const
390                { return this->functionPointer_; }
[7179]391
[7401]392            // see Functor::getFullIdentifier()
[10876]393            const std::type_index getFullIdentifier() const
[7212]394                { return typeid(F); }
[7179]395
[7212]396        protected:
[7401]397            F functionPointer_;     ///< The stored function-pointer
[7212]398    };
[7179]399
[7212]400    namespace detail
[7179]401    {
[7401]402        // Helper class to get the type of the function pointer with the given class, parameters, return-value, and constness
[10876]403        template <class R, class O, bool isconst, class... Params> struct FunctionPointer                                   { typedef R (O::*Type)(Params...); };
404        template <class R, class O, class... Params>               struct FunctionPointer<R, O, true, Params...>            { typedef R (O::*Type)(Params...) const; };
405        template <class R, class... Params>                        struct FunctionPointer<R, void, false, Params...>        { typedef R (*Type)(Params...); };
[7179]406
[7401]407        // Helper class, used to call a function-pointer with a given object and parameters and to return its return-value (if available)
[10876]408        template <class R, class O, bool isconst, class... Params>         struct FunctorCaller                                        { static inline MultiType call(typename detail::FunctionPointer<R, O, isconst, Params...>::Type functionPointer, O* object, const Params&... parameters)    { return (object->*functionPointer)(parameters...); } };
409        template <class O, bool isconst, class... Params>                  struct FunctorCaller<void, O, isconst, Params...>           { static inline MultiType call(typename detail::FunctionPointer<void, O, isconst, Params...>::Type functionPointer, O* object, const Params&... parameters) { (object->*functionPointer)(parameters...); return MultiType::Null; } };
410        template <class R, bool isconst, class... Params>                  struct FunctorCaller<R, void, isconst, Params...>           { static inline MultiType call(typename detail::FunctionPointer<R, void, isconst, Params...>::Type functionPointer, void*, const Params&... parameters)     { return (*functionPointer)(parameters...); } };
411        template <bool isconst, class... Params>                           struct FunctorCaller<void, void, isconst, Params...>        { static inline MultiType call(typename detail::FunctionPointer<void, void, isconst, Params...>::Type functionPointer, void*, const Params&... parameters)  { (*functionPointer)(parameters...); return MultiType::Null; } };
[7179]412
[7401]413        // Helper class, used to identify the header of a function-pointer (independent of its class)
[10876]414        template <class R, class... Params>
[7212]415        struct FunctorHeaderIdentifier
416        {};
[7179]417
[7401]418        // Helper class to determine if a function has a returnvalue
[7213]419        template <class T>
[7212]420        struct FunctorHasReturnvalue
421        { enum { result = true }; };
422        template <>
423        struct FunctorHasReturnvalue<void>
424        { enum { result = false }; };
[1505]425
[10876]426        //Barebones implementation of (make_)index_sequence for C++11
427        template <std::size_t...> struct index_sequence {};
428
429        template <std::size_t N, std::size_t... Is>
430        struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};
431
432        template <std::size_t... Is>
433        struct make_index_sequence<0u, Is...> : index_sequence<Is...> {};
434
435        //Helper structs to deduce the first N types of a parameter pack
436        template<class... Types> struct type_list {};
437
438        template <class T1, class... AllTypes>
439        struct make_type_list_helper
440        {
441            template <std::size_t N, class... Types>
442            struct make_type_list_impl : make_type_list_helper<AllTypes...>::template make_type_list_impl<N - 1, Types..., T1> {};
443
444            template <class... Types>
445            struct make_type_list_impl<1u, Types...> : type_list<Types..., T1> {};
446        };
447
448        template <std::size_t N, class... Types>
449        struct make_type_list : make_type_list_helper<Types...>::template make_type_list_impl<N> {};
450
451        template <class... Types>
452        struct make_type_list<0u, Types...> : type_list<> {};
[1505]453    }
454
[7401]455    /**
456        @brief FunctorTemplate is a child class of FunctorPointer and implements all functions
457        that need to know the exact types of the parameters, return-value, and class.
458
459        @param R The type of the return-value of the function
460        @param O The class of the function
461        @param isconst True if the function is a const member-function
[10975]462        @param Params The types of the parameters
[7401]463
464        This template has many parameters and is usually not used directly. It is created by
465        createFunctor(), but only the base-classes Functor, FunctorMember, and FunctorPointer
466        are used directly. It implements all the virtual functions that are declared by its
467        base classes.
468
469        All template arguments can be void.
470    */
[10876]471    template <class R, class O, bool isconst, class... Params>
472    class FunctorTemplate : public FunctorPointer<typename detail::FunctionPointer<R, O, isconst, Params...>::Type, O>
[7212]473    {
[10876]474        static_assert(sizeof...(Params) <= 5, "Only up to 5 parameters are supported");
475
[7212]476        public:
[7401]477            /// Constructor: Initializes the base class.
[10876]478            FunctorTemplate(typename detail::FunctionPointer<R, O, isconst, Params...>::Type functionPointer, O* object = nullptr) : FunctorPointer<typename detail::FunctionPointer<R, O, isconst, Params...>::Type, O>(functionPointer, object) {}
[1505]479
[7401]480            // see FunctorMember::operator()()
[10876]481            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
[7212]482            {
[10876]483                auto multis = std::make_tuple(param1, param2, param3, param4, param5);
484                return callHelper(object, multis, detail::make_index_sequence<sizeof...(Params)>{});
[7212]485            }
[1505]486
[7401]487            // see Functor::clone()
[10876]488            virtual FunctorPtr clone() override
[7270]489            {
[10825]490                return std::make_shared<FunctorTemplate>(*this);
[7270]491            }
492
[7401]493            // see Functor::evaluateArgument()
[10876]494            virtual void evaluateArgument(unsigned int index, MultiType& argument) const override
[7212]495            {
[10876]496                static const std::array<std::function<bool(MultiType&)>, sizeof...(Params)> funcs = {&MultiType::convert<Params>...};
497                if (index < funcs.size())
[7212]498                {
[10876]499                    funcs[index](argument);
[7212]500                }
501            }
[1505]502
[7401]503            // see Functor::getParamCount()
[10876]504            virtual unsigned int getParamCount() const override
[7212]505            {
[10876]506                return sizeof...(Params);
[7212]507            }
[1505]508
[7401]509            // see Functor::hasReturnvalue()
[10876]510            virtual bool hasReturnvalue() const override
[7212]511            {
512                return detail::FunctorHasReturnvalue<R>::result;
513            }
[1505]514
[7401]515            // see Functor::getTypenameParam()
[10876]516            virtual std::string getTypenameParam(unsigned int index) const override
[7212]517            {
[10876]518                static const std::array<std::string, sizeof...(Params)> names = { typeToString<Params>()... };
519                if (index >= names.size())
[7212]520                {
[10876]521                    return "";
[7212]522                }
[10876]523                return names[index];
[7212]524            }
[1505]525
[7401]526            // see Functor::getTypenameReturnvalue()
[10876]527            virtual std::string getTypenameReturnvalue() const override
[7212]528            {
529                return typeToString<R>();
530            }
[7179]531
[7401]532            // see Functor::getHeaderIdentifier()
[10876]533            virtual const std::type_index getHeaderIdentifier() const override
[7212]534            {
[10876]535                return typeid(detail::FunctorHeaderIdentifier<R, Params...>);
[7212]536            }
[7214]537
[7401]538            // see Functor::getHeaderIdentifier(unsigned int)
[10876]539            virtual const std::type_index getHeaderIdentifier(unsigned int params) const override
[7214]540            {
[10876]541                //+1 because e.g. for two parameters, we want typeids for zero, one, or two parameters
542                return getHeaderIdentifierHelper(params, detail::make_index_sequence<sizeof...(Params) + 1>{});
543            }
544
545    private:
546
547            /// Helper function that extracts index numbers of parameters from a tuple. Needed to call the function pointer with the correct amount of arguments.
548            template<typename Tup, std::size_t... index>
549            MultiType callHelper(O* object, Tup&& tup, detail::index_sequence<index...>)
550            {
551                return detail::FunctorCaller<R, O, isconst, Params...>::call(this->functionPointer_, object, std::get<index>(std::forward<Tup>(tup))...);
552            }
553
554            /// Helper function to extract all identifiers of the function pointer using a deduced index sequence
555            template<std::size_t... index>
556            const std::type_index& getHeaderIdentifierHelper(unsigned int params, detail::index_sequence<index...>) const
557            {
558                static const std::array<const std::type_index, sizeof...(index)> typeinfos = { getTypelistIdentifier(detail::make_type_list<index, Params...>{})... };
559                if (params >= typeinfos.size())
[7214]560                {
[10876]561                    return typeinfos.back();
[7214]562                }
[10876]563                return typeinfos[params];
[7214]564            }
[10876]565
566            ///Helper function that deduces a parameter pack of types and returns the corresponding identifier
567            template<class... Types>
568            const std::type_index getTypelistIdentifier(detail::type_list<Types...>) const
569            {
570                return typeid(detail::FunctorHeaderIdentifier<R, Types...>);
571            }
[7212]572    };
[1505]573
[10975]574
575    /**
576    @brief FunctorCallable is a child class of FunctorTemplate. It stores a callable
577    object (e.g. a lambda or a class with operator()) inside and acts like any
578    other functor. Note that it stores a \em copy of the object, not a reference or a pointer.
579    Take care that this functor does not outlive objects that have been captured by reference
580    in a lambda.
581
582    @param F The type of the callable object
583    @param R The type of the return-value of the function
584    @param isconst True if operator() is const
585    @param Params The types of the parameters
586
587    This template can not be used directly when using lambdas - the type of a lambda
588    is not specified. It can only really be used through the base-class Functor.
589    */
590    template <class F, class R, bool isconst, class... Params>
591    class FunctorCallable : public FunctorTemplate<R, F, isconst, Params...>
592    {
593    public:
594        FunctorCallable(const F& obj): FunctorTemplate<R, F, isconst, Params...>(&F::operator(), &obj_)
595            , obj_(obj)
596        {}
597
598    private:
599        F obj_; ///< The callable object
600    };
601
602    namespace detail
603    {
604        //Helper functions to deduce types and constness of operator() and return the correct FunctorCallable
605        template <class F, class R, class... Params> inline FunctorMemberPtr<F> callableHelper(const F& obj, R(F::*func)(Params...) const) { return std::make_shared<FunctorCallable<F, R, true, Params...>>(obj); }
606        template <class F, class R, class... Params> inline FunctorMemberPtr<F> callableHelper(const F& obj, R(F::*func)(Params...)) { return std::make_shared<FunctorCallable<F, R, false, Params...>>(obj); }
607    }
608
[10876]609    template <class R, class O, class OO, class... Params> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(Params...), OO* object) { return std::make_shared<FunctorTemplate<R, O, false, Params...>>(functionPointer, object); }   ///< Creates a new FunctorMember with the given function-pointer and an assigned object
610    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<R, O, true, Params...>>(functionPointer, object); }   ///< Creates a new FunctorMember with the given function-pointer and an assigned object
[1505]611
[10876]612    template <class R, class O, class... Params> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(Params...)) { return std::make_shared<FunctorTemplate<R, O, false, Params...>>(functionPointer); }   ///< Creates a new FunctorMember with the given function-pointer
613    template <class R, class O, class... Params> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(Params...) const) { return std::make_shared<FunctorTemplate<R, O, true, Params...>>(functionPointer); }   ///< Creates a new FunctorMember with the given function-pointer
[1505]614
[10876]615    template <class R, class... Params> inline FunctorStaticPtr createFunctor(R (*functionPointer)(Params...)) { return std::make_shared<FunctorTemplate<R, void, false, Params...>>(functionPointer); }   ///< Creates a new Functor with the given function-pointer
[10975]616   
617    template <class F> inline FunctorMemberPtr<F> createFunctor(const F& obj) { return detail::callableHelper(obj, &F::operator()); } ///< Creates a new Functor with a callable object
[1505]618}
619
620#endif /* _Functor_H__ */
Note: See TracBrowser for help on using the repository browser.