Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Dec 28, 2015, 6:57:26 PM (8 years ago)
Author:
landauf
Message:

use the existing class 'FunctorPointer' to store the callable object. functors with callable objects (e.g. lambdas) are now treated as static functors.
this also fixes an issue on gcc: because of a bug, gcc was not able to store the function pointer of a lambda's operator() https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51048. storing the whole object is apparently a workaround for this issue.

Note: tests currently fail on MSVC because it doesn't accept std::function as a callable object.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • code/branches/cpp11_v2/src/libraries/core/command/Functor.h

    r10985 r10986  
    357357
    358358    /**
    359         @brief FunctorPointer is a child class of FunctorMember and expands it with a function-pointer.
    360         @param F The type of the function-pointer
    361         @param O The type of the function's class (or void if it's a static function)
     359        @brief FunctorPointer is a child class of FunctorMember and extends it with a function-pointer (or a function-object).
     360        @param F The type of the function-pointer (or the function-object)
     361        @param O The type of the function's class (or void if it's a static function or a function-object)
    362362
    363363        The template FunctorPointer has an additional template parameter that defines the type
    364         of the function-pointer. This can be handy if you want to get or set the function-pointer.
    365         You can then use a static_cast to cast a Functor to FunctorPointer if you know the type
    366         of the function-pointer.
     364        of the function-pointer (or the function-object). This can be handy if you want to get
     365        or set the function-pointer (or the function-object). You can then use a static_cast
     366        to cast a Functor to FunctorPointer if you know the type of the function.
    367367
    368368        However FunctorPointer is not aware of the types of the different parameters or the
     
    383383                { return this->functionPointer_; }
    384384
    385             // see Functor::getFullIdentifier()
    386             virtual const std::type_info& getFullIdentifier() const override
    387                 { return typeid(F); }
    388 
    389385        protected:
    390386            F functionPointer_;     ///< The stored function-pointer
     
    393389    namespace detail
    394390    {
    395         // Helper class to get the type of the function pointer with the given class, parameters, return-value, and constness
    396         template <class R, class O, bool isconst, class... Params> struct FunctionPointer                            { typedef R (O::*Type)(Params...); };
    397         template <class R, class O, class... Params>               struct FunctionPointer<R, O, true, Params...>     { typedef R (O::*Type)(Params...) const; };
    398         template <class R, class... Params>                        struct FunctionPointer<R, void, false, Params...> { typedef R (*Type)(Params...); };
    399 
    400         // Helper class, used to call a function-pointer with a given object and parameters and to return its return-value (if available)
    401         template <class R, class O, bool isconst, class... Params> struct FunctorCaller                                 { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionPointer<R, O, isconst, Params...>::Type       functionPointer, O* object, const Params&... parameters, const UnusedParams&...) { return (object->*functionPointer)(parameters...); } };
    402         template <class O, bool isconst, class... Params>          struct FunctorCaller<void, O, isconst, Params...>    { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionPointer<void, O, isconst, Params...>::Type    functionPointer, O* object, const Params&... parameters, const UnusedParams&...) { (object->*functionPointer)(parameters...); return MultiType::Null; } };
    403         template <class R, bool isconst, class... Params>          struct FunctorCaller<R, void, isconst, Params...>    { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionPointer<R, void, isconst, Params...>::Type    functionPointer, void*,     const Params&... parameters, const UnusedParams&...) { return (*functionPointer)(parameters...); } };
    404         template <bool isconst, class... Params>                   struct FunctorCaller<void, void, isconst, Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionPointer<void, void, isconst, Params...>::Type functionPointer, void*,     const Params&... parameters, const UnusedParams&...) { (*functionPointer)(parameters...); return MultiType::Null; } };
     391        // Helper class to get the type of the function-pointer (or the function-object) with the given class, parameters, return-value, and constness
     392        template <class F, class R, class O, bool isconst, class... Params> struct FunctionType /* generic type is undefined */;
     393        template <         class R, class O,               class... Params> struct FunctionType<void, R, O,    false, Params...> { typedef R (O::*Type)(Params...); };       // spezialization: non-const member function
     394        template <         class R, class O,               class... Params> struct FunctionType<void, R, O,    true,  Params...> { typedef R (O::*Type)(Params...) const; }; // spezialization: const member function
     395        template <         class R,                        class... Params> struct FunctionType<void, R, void, false, Params...> { typedef R (*Type)(Params...); };          // spezialization: static function
     396        template <class F, class R,                        class... Params> struct FunctionType<F,    R, void, false, Params...> { typedef F Type; };                        // spezialization: function object
     397
     398        // Helper class, used to call a function with a given object and parameters and to return its return-value (if available)
     399        template <class F, class R, class O, bool isconst, class... Params> struct FunctorCaller /* generic type is undefined */;
     400        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
     401        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
     402        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
     403        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
     404        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
     405        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
    405406
    406407        // Helper class to determine if a function has a returnvalue
     
    457458        that need to know the exact types of the parameters, return-value, and class.
    458459
     460        @param F the type of the function-object (or void if a function-pointer is used).
    459461        @param R The type of the return-value of the function
    460462        @param O The class of the function
     
    469471        All template arguments can be void.
    470472    */
    471     template <class R, class O, bool isconst, class... Params>
    472     class FunctorTemplate : public FunctorPointer<typename detail::FunctionPointer<R, O, isconst, Params...>::Type, O>
     473    template <class F, class R, class O, bool isconst, class... Params>
     474    class FunctorTemplate : public FunctorPointer<typename detail::FunctionType<F, R, O, isconst, Params...>::Type, O>
    473475    {
    474476        static_assert(sizeof...(Params) <= 5, "Only up to 5 parameters are supported");
     
    476478        public:
    477479            /// Constructor: Initializes the base class.
    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) {}
     480            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) {}
    479481
    480482            // see FunctorMember::operator()()
    481483            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
    482484            {
    483                 return detail::FunctorCaller<R, O, isconst, Params...>::call(this->functionPointer_, object, param1, param2, param3, param4, param5);
     485                return detail::FunctorCaller<F, R, O, isconst, Params...>::call(this->functionPointer_, object, param1, param2, param3, param4, param5);
    484486            }
    485487
     
    535537            }
    536538
     539            // see Functor::getFullIdentifier()
     540            virtual const std::type_info& getFullIdentifier() const override
     541            {
     542                return typeid(typename detail::FunctionType<void, R, O, isconst, Params...>::Type);
     543            }
     544
    537545            // see Functor::getHeaderIdentifier()
    538546            virtual const std::type_info& getHeaderIdentifier() const override
    539547            {
    540                 return typeid(typename detail::FunctionPointer<R, void, false, Params...>::Type);
     548                return typeid(typename detail::FunctionType<void, R, void, false, Params...>::Type);
    541549            }
    542550
     
    560568            const std::type_info& getTypelistIdentifier(detail::type_list<Types...>) const
    561569            {
    562                 return typeid(typename detail::FunctionPointer<R, void, false, Types...>::Type);
     570                return typeid(typename detail::FunctionType<void, R, void, false, Types...>::Type);
    563571            }
    564572    };
    565573
    566574
    567     /**
    568     @brief FunctorCallable is a child class of FunctorTemplate. It stores a callable
    569     object (e.g. a lambda or a class with operator()) inside and acts like any
    570     other functor. Note that it stores a \em copy of the object, not a reference or a pointer.
    571     Take care that this functor does not outlive objects that have been captured by reference
    572     in a lambda.
    573 
    574     @param F The type of the callable object
    575     @param R The type of the return-value of the function
    576     @param isconst True if operator() is const
    577     @param Params The types of the parameters
    578 
    579     This template can not be used directly when using lambdas - the type of a lambda
    580     is not specified. It can only really be used through the base-class Functor.
    581     */
    582     template <class F, class R, bool isconst, class... Params>
    583     class FunctorCallable : public FunctorTemplate<R, F, isconst, Params...>
    584     {
    585     public:
    586         FunctorCallable(const F& obj): FunctorTemplate<R, F, isconst, Params...>(&F::operator(), &obj_)
    587             , obj_(obj)
    588         {}
    589 
    590     private:
    591         F obj_; ///< The callable object
    592     };
    593 
    594575    namespace detail
    595576    {
    596577        //Helper functions to deduce types and constness of operator() and return the correct FunctorCallable
    597         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); }
    598         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); }
     578        template <class F, class R, class... Params> inline FunctorStaticPtr callableHelper(const F& functionObject, R(F::*)(Params...))       { return std::make_shared<FunctorTemplate<F, R, void, false, Params...>>(functionObject); }
     579        template <class F, class R, class... Params> inline FunctorStaticPtr callableHelper(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.
    599580    }
    600581
    601     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
    602     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
    603 
    604     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
    605     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
    606 
    607     template <class R, class... Params> inline FunctorStaticPtr createFunctor(R (*functionPointer)(Params...)) { return std::make_shared<FunctorTemplate<R, void, false, Params...>>(functionPointer); } ///< Creates a new FunctorStatic with the given function-pointer
    608    
    609     template <class F> inline FunctorMemberPtr<F> createFunctor(const F& obj) { return detail::callableHelper(obj, &F::operator()); } ///< Creates a new Functor with a callable object
     582    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
     583    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
     584
     585    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
     586    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
     587
     588    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
     589
     590    /** Take care that this functor does not outlive objects that have been captured by reference in a lambda. */
     591    template <class F> inline FunctorStaticPtr createFunctor(const F& functionObject) { return detail::callableHelper(functionObject, &F::operator()); } ///< Creates a new Functor with a callable object
    610592}
    611593
Note: See TracChangeset for help on using the changeset viewer.