C/C++ 11/14 rewrites a std::function<…> function template that supports safety and no multiple copies, supports Lambda λ and overloaded operator()(…) operator structure and C/C++ language Ordinary functions.

As the title of this article indicates, it was rewritten for optimization, and the solid-size BUFF buffer provided by the standard library std::function implementation was cut off because it is no longer necessary. The implementation copies the shared pointer. Reference, instead of needing to copy the BUFF and reconstruct it like the official version. If the structure exceeds the BUFF size, heap memory will be allocated from the system during the STL runtime. This version uses the method you want to use for heap memory allocation.

Supported features:

1. NULL (macro)

2. nullptr (null pointer keyword introduced in C++11)

3. Lambda ordinary function

4. Lambda closure function

5. Ordinary C/C++ function binding

6. Only copy the closure structure once to reduce memory copy problems.

7. EMC-MCx multi-thread security support

8. Highly efficient template source code implementation

9. C++ 11, 14 standard compiler support

10. It is allowed to derive subclasses and rewrite base class functions according to the L principle Liskov substitution. It can be used for AOP aspect programming to process transaction logs, etc.

11. Support Void no return value type return

12. Support std::move, rvalue reference lossless move function internal managed field.

Practical example:

 bool(*xxx)(int, int);
    ppp::function<bool(int x, int y)> x0 = xxx;
    ppp::function<bool(int x, int y)> x2 = NULL;
    ppp::function<bool(int x, int y)> x1 = [](int x, int y)
    {
        return x > y;
    };
    ppp::function<bool(int x, int y)> x3 = [ & amp;argc](int x, int y)
    {
        return x > y;
    };
    x0.swap(x2);
    x1(100, 200);
    x3(300, 400);

Template implementation:

stl::is_invocable<...> implementation

 template <typename F, typename... Args>
    class is_invocable {
        template <typename U>
        static auto test(int) -> decltype(std::declval<U>()(std::declval<Args>()...), std::true_type());

        template <typename U>
        static std::false_type test(...);

    public:
        static constexpr bool value = std::is_same<decltype(test<F>(0)), std::true_type>::value;
    };

ppp::function<...> implementation

 template <typename Signature>
    class function;

    template <typename R, typename... Args>
    class function<R(Args...)> {
    public:
        using Function = R(*)(Args...);

    public:
        function() noexcept : lk_(false), f_(NULL) {}
        function(std::nullptr_t) noexcept : lk_(false), f_(NULL) {}
        function(function & amp; & amp; other) noexcept {
            move(std::forward<function>(other));
        }
        function(const function & amp; other) noexcept {
            LockScope<typename std::decay<decltype(*this)>::type> scope(const_cast<function &>(other));
            this->f_ = other.f_;
            this->callable_ = other.callable_;
        }

    public:
        template <typename F>
        function(F & amp; & amp; f) noexcept {
            constructor(std::forward<F>(f));
        }

    private:
        template <typename F>
        typename std::enable_if<std::is_convertible<typename std::decay<F>::type, Function>::value, void>::type
        inline constructor_fx(F & amp; & amp; f) noexcept {
            const Function fx = static_cast<Function>(f);
            reset(fx);
        }

        template <typename F>
        typename std::enable_if<!std::is_convertible<typename std::decay<F>::type, Function>::value, void>::type
        inline constructor_fx(F & amp; & amp; f) noexcept {
            reset(std::forward<F>(f));
        }

        template <typename F>
        typename std::enable_if<std::is_same<typename std::decay<F>::type, Function>::value, void>::type
        inline constructor_rt(F & amp; f) noexcept {
            const Function fx = static_cast<Function>(f);
            reset(fx);
        }

        template <typename F>
        typename std::enable_if<!std::is_same<typename std::decay<F>::type, Function>::value, void>::type
        inline constructor_rt(F & amp; & amp; f) noexcept {
            constructor_fx(f);
        }

        template <typename F>
        typename std::enable_if<stl::is_invocable<typename std::decay<F>::type, Args...>::value, void>::type
        inline constructor(F & amp; & amp; f) noexcept {
            constructor_rt(std::forward<F>(f));
        }

        template <typename F>
        typename std::enable_if<!stl::is_invocable<typename std::decay<F>::type, Args...>::value, void>::type
        inline constructor(F & amp; & amp;) noexcept {
            reset();
        }

    public:
        virtual ~function() noexcept {
            reset();
        }

    public:
        inline function & amp; operator=(function & amp; & amp; other) noexcept {
            move(std::forward<function>(other));
            return *this;
        }
        inline function & amp; operator=(const function & amp; other) noexcept {
            function* const reft = (function*) & amp;reinterpret_cast<const char & amp;>(other);
            function* const left = this;
            if (left != reft) {
                // Copy the field value on the right to the top of the stack.
                Function reft_f = NULL;
                std::shared_ptr<ICallable> reft_callable;
                {
                    LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function &>(other));
                    reft_f = other.f_;
                    reft_callable = other.callable_;
                }

                // Writes the field value stored on the stack to the corresponding field of this function object.
                {
                    LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
                    this->f_ = reft_f;
                    this->callable_ = reft_callable;
                }
            }
            return *left;
        }
        inline function & amp; operator=(std::nullptr_t) {
            reset();
            return *this;
        }
        inline explicit operator bool() const {
            using TFunctionConst = typename std::decay<decltype(*this)>::type;
            using TFunctionMutable = typename std::remove_const<TFunctionConst>::type;

            LockScope<TFunctionMutable> scope(const_cast<TFunctionMutable &>(*this));
            return NULL != f_ || NULL != callable_;
        }

    public:
        virtual R operator()(Args... args) const {
            using TFunctionConst = typename std::decay<decltype(*this)>::type;
            using TFunctionMutable = typename std::remove_const<TFunctionConst>::type;

            // Calls still first synchronize the destination function address,
            // held from the function object or wrap a reference to the calling object onto the stack.
            do {
                Function f = NULL;
                std::shared_ptr<ICallable> i;
                {
                    LockScope<TFunctionMutable> scope(const_cast<TFunctionMutable &>(*this));
                    f = this->f_;
                    i = this->callable_;
                }

                if (NULL != i) {
                    return i->Invoke(std::forward<Args>(args)...);
                }

                if (NULL != f) {
                    return f(std::forward<Args>(args)...);
                }
            } while (false);

            // It may be a thread-safe issue to throw an exception for the caller to catch
            // if the current function object is not a null pointer.
            throw std::runtime_error("Cannot call a function with an null address delegated.");
        }

    public:
        inline void swap(function & amp; other) noexcept {
            // Copy the field values of the function on the left.
            Function left_f = NULL;
            std::shared_ptr<ICallable> left_callable;
            {
                LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
                left_f = this->f_;
                left_callable = this->callable_;
            }

            // Copy the field values of the function on the right.
            Function reft_f = NULL;
            std::shared_ptr<ICallable> reft_callable;
            {
                LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function &>(other));
                reft_f = other.f_;
                reft_callable = other.callable_;
            }

            // Formally replace the values on both sides, but in the process of exchange,
            // high concurrency may occur and the newly written field values will be overwritten,
            // there will be new and old data overwriting problems, developers need to use the function carefully,
            // or ensure the linearity of the logic outside.
            {
                LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
                this->f_ = reft_f;
                this->callable_ = reft_callable;
            }

            // Swap the value on the left to the function object on the right.
            {
                LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function &>(other));
                other.f_ = left_f;
                other.callable_ = left_callable;
            }
        }
        inline void reset() noexcept {
            LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
            reset_unsafe();
        }
        inline void reset(const Function & amp; f) noexcept {
            LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
            reset_unsafe(f);
        }

        template <typename F>
        inline void reset(F & amp; & amp; f) noexcept {
            LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
            reset_unsafe(std::forward<F>(f));
        }

    private:
        inline void reset_unsafe() noexcept {
            this->f_ = NULL;
            this->callable_.reset();
        }
        inline void reset_unsafe(const Function & amp; f) noexcept {
            reset_unsafe();

            this->f_ = f;
        }

        template <typename F>
        inline void reset_unsafe(F & amp; & amp; f) noexcept {
            reset_unsafe_bind<R>(std::forward<F>(f));
        }

        template <typename E, typename F>
        typename std::enable_if<!std::is_same<E, void>::value, void>::type
        inline reset_unsafe_bind(F & amp; & amp; f) noexcept {
            using TFunction = typename std::decay<F>::type;
            using TCallable = Callable<TFunction>;

            reset_unsafe_bind_fx<F, TFunction, TCallable>(std::forward<F>(f));
        }

        template <typename E, typename F>
        typename std::enable_if<std::is_same<E, void>::value, void>::type
        inline reset_unsafe_bind(F & amp; & amp; f) noexcept {
            using TFunction = typename std::decay<F>::type;
            using TCallable = CallableVoid<TFunction>;

            reset_unsafe_bind_fx<F, TFunction, TCallable>(std::forward<F>(f));
        }

        template <typename F, typename TFunction, typename TCallable>
        inline void reset_unsafe_bind_fx(F & amp; & amp; f) noexcept {
            reset_unsafe();

            TCallable* fx = new TCallable(std::forward<TFunction>(f));
            if (NULL != fx) {
                this->callable_ = std::shared_ptr<TCallable>(fx);
            }
        }

    private:
        inline void lock() noexcept {
            for (;;) {
                bool expected = false;
                if (lk_.compare_exchange_strong(expected, true, std::memory_order_acquire)) {
                    break;
                }
            }
        }
        inline void unlock() {
            bool expected = true;
            if (!lk_.compare_exchange_strong(expected, false, std::memory_order_release)) {
                throw std::runtime_error("failed to acquire the atomic lock.");
            }
        }
        inline void move(function & amp; & amp; other) noexcept {
            Function left_f = NULL;
            std::shared_ptr<ICallable> left_callable; // COW.
            {
                // Move and copy the field value of the right function object to the left function object.
                LockScope<typename std::decay<decltype(*this)>::type> scope(other);
                left_f = other.f_;
                left_callable = std::move(other.callable_);

                // Reset and release the field value reference technique held by the function object on the right and so on.
                other.f_ = NULL;
                other.callable_.reset();
            }

            // Writes the field value stored on the stack to the corresponding field of this function object.
            {
                LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
                this->f_ = left_f;
                this->callable_ = left_callable;
            }
        }

    private:
        class ICallable {
        public:
            ICallable() = default;
            virtual ~ICallable() noexcept {}

        public:
            virtual R Invoke(Args & amp; & amp;... args) const = 0;
        };

        template <typename F>
        class Callable : public ICallable {
        public:
            Callable(F & amp; & amp; f) noexcept : f_(std::forward<F>(f)) {}
            virtual ~Callable() noexcept {}

        public:
            virtual R Invoke(Args & amp; & amp;... args) const override {
                return f_(std::forward<Args>(args)...);
            }

        private:
            mutable F f_;
        };

        template <typename F>
        class CallableVoid : public ICallable {
        public:
            CallableVoid(F & amp; & amp; f) noexcept : f_(std::forward<F>(f)) {}
            virtual ~CallableVoid() noexcept {}

        public:
            virtual R Invoke(Args & amp; & amp;... args) const override {
                f_(std::forward<Args>(args)...);
                return R{};
            }

        private:
            mutable F f_;
        };

        template <typename T>
        class LockScope {
        public:
            LockScope(T & obj) noexcept
                : obj_(obj) {
                obj_.lock();
            }
            ~LockScope() noexcept {
                obj_.unlock();
            }

        private:
            T & obj_;
        };

    private:
        mutable std::atomic<bool>lk_;
        mutable Function f_;
        mutable std::shared_ptr<ICallable> callable_; // COW.
    };

    template <class F>
    inline bool operator==(const function<F> & amp; other, std::nullptr_t) noexcept {
        return !other;
    }

    template <class F>
    inline bool operator==(std::nullptr_t, const function<F> & amp; other) noexcept {
        return !other;
    }

    template <class F>
    inline bool operator!=(const function<F> & amp; other, std::nullptr_t) noexcept {
        return static_cast<bool>(other);
    }

    template <class F>
    inline bool operator!=(std::nullptr_t, const function<F> & amp; other) noexcept {
        return static_cast<bool>(other);
    }

C++17 implementation

 template <typename Signature>
    class function;

    template <typename R, typename... Args>
    class function<R(Args...)> {
    public:
        using Function = R(*)(Args...);

    public:
        function() noexcept {}
        function(std::nullptr_t) noexcept {}
        function(function & amp; & amp; other) noexcept {
            move(std::forward<function>(other));
        }
        function(const function & amp; other) noexcept {
            LockScope<typename std::decay<decltype(*this)>::type> scope(const_cast<function &>(other));
            this->f_ = other.f_;
            this->callable_ = other.callable_;
        }

    public:
        template <typename F>
        function(F & amp; & amp; f) {
            reset(std::forward<F>(f));
        }

    public:
        virtual ~function() noexcept {
            reset();
        }

    public:
        inline function & amp; operator=(function & amp; & amp; other) noexcept {
            move(std::forward<function>(other));
            return *this;
        }
        inline function & amp; operator=(const function & amp; other) noexcept {
            function* const reft = (function*) & amp;reinterpret_cast<const char & amp;>(other);
            function* const left = this;
            if (left != reft) {
                // Copy the field value on the right to the top of the stack.
                Function reft_f = NULL;
                std::shared_ptr<ICallable> reft_callable;
                {
                    LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function &>(other));
                    reft_f = other.f_;
                    reft_callable = other.callable_;
                }

                // Writes the field value stored on the stack to the corresponding field of this function object.
                {
                    LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
                    this->f_ = reft_f;
                    this->callable_ = reft_callable;
                }
            }
            return *left;
        }
        inline function & amp; operator=(std::nullptr_t) {
            reset();
            return *this;
        }
        inline explicit operator bool() const {
            using TFunctionConst = typename std::decay<decltype(*this)>::type;
            using TFunctionMutable = typename std::remove_const<TFunctionConst>::type;

            LockScope<TFunctionMutable> scope(const_cast<TFunctionMutable &>(*this));
            return NULL != f_ || NULL != callable_;
        }

    public:
        virtual R operator()(Args... args) const {
            using TFunctionConst = typename std::decay<decltype(*this)>::type;
            using TFunctionMutable = typename std::remove_const<TFunctionConst>::type;

            // Calls still first synchronize the destination function address,
            // held from the function object or wrap a reference to the calling object onto the stack.
            do {
                Function f = NULL;
                std::shared_ptr<ICallable> i;
                {
                    LockScope<TFunctionMutable> scope(const_cast<TFunctionMutable &>(*this));
                    f = this->f_;
                    i = this->callable_;
                }

                if (NULL != i) {
                    return i->Invoke(std::forward<Args>(args)...);
                }

                if (NULL != f) {
                    return f(std::forward<Args>(args)...);
                }
            } while (false);

            // It may be a thread-safe issue to throw an exception for the caller to catch
            // if the current function object is not a null pointer.
            throw std::runtime_error("Cannot call a function with an null address delegated.");
        }

    public:
        inline void swap(function & amp; other) noexcept {
            // Copy the field values of the function on the left.
            Function left_f = NULL;
            std::shared_ptr<ICallable> left_callable;
            {
                LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
                left_f = this->f_;
                left_callable = this->callable_;
            }

            // Copy the field values of the function on the right.
            Function reft_f = NULL;
            std::shared_ptr<ICallable> reft_callable;
            {
                LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function &>(other));
                reft_f = other.f_;
                reft_callable = other.callable_;
            }

            // Formally replace the values on both sides, but in the process of exchange,
            // high concurrency may occur and the newly written field values will be overwritten,
            // there will be new and old data overwriting problems, developers need to use the function carefully,
            // or ensure the linearity of the logic outside.
            {
                LockScope<typename std::decay<decltype(*this)>::type> left_scope(*this);
                this->f_ = reft_f;
                this->callable_ = reft_callable;
            }

            // Swap the value on the left to the function object on the right.
            {
                LockScope<typename std::decay<decltype(*this)>::type> reft_scope(const_cast<function &>(other));
                other.f_ = left_f;
                other.callable_ = left_callable;
            }
        }
        inline void reset() noexcept {
            LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
            this->f_ = NULL;
            this->callable_.reset();
        }
        inline void reset(const Function & amp; f) noexcept {
            LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
            this->f_ = f;
            this->callable_.reset();
        }

        template <typename F>
        inline void reset(F & amp; & amp; f) {
            using TFunction = typename std::decay<F>::type;
            using TSynchronizedObject = typename std::decay<decltype(*this)>::type;

            LockScope<TSynchronizedObject> scope(*this);
            reset<F, TFunction>(std::forward<F>(f));
        }

    private:
        template <typename F, typename TFunction>
        inline void reset(F & amp; & amp; f) {
            this->f_ = NULL;
            this->callable_.reset();

            if constexpr (std::is_same<Function, TFunction>::value) {
                this->f_ = f;
                this->callable_ = NULL;
            }
            elif constexpr (std::is_same<function, TFunction>::value) {
                this->f_ = f.f_;
                this->callable_ = f.callable_;
            }
            elif constexpr (std::is_empty<TFunction>::value) {
                static_assert(stl::is_invocable<TFunction, Args...>::value, "Unknown expressions, not supported!");

                this->f_ = f;
                this->callable_ = NULL;
            }
            elif constexpr (std::is_integral<TFunction>::value) {
                if (f != 0) {
                    throw std::runtime_error("It's not allowed to pass an integer value to the constructor, but it's allowed to pass an integer 0 to the constructor of a function, which represents a NULL function pointer." );
                }
            }
            else {
                using TCallable = Callable<TFunction>;

                TCallable* fx = new TCallable(std::forward<TFunction>(f));
                if (NULL != fx) {
                    this->callable_ = std::shared_ptr<TCallable>(fx);
                }
            }
        }

    private:
        inline void lock() noexcept {
            for (;;) {
                bool expected = false;
                if (lk_.compare_exchange_strong(expected, true, std::memory_order_acquire)) {
                    break;
                }
            }
        }
        inline void unlock() {
            bool expected = true;
            if (!lk_.compare_exchange_strong(expected, false, std::memory_order_release)) {
                throw std::runtime_error("failed to acquire the atomic lock.");
            }
        }
        inline void move(function & amp; & amp; other) noexcept {
            Function left_f = NULL;
            std::shared_ptr<ICallable> left_callable; // COW.
            {
                // Move and copy the field value of the right function object to the left function object.
                LockScope<typename std::decay<decltype(*this)>::type> scope(other);
                left_f = other.f_;
                left_callable = std::move(other.callable_);

                // Reset and release the field value reference technique held by the function object on the right and so on.
                other.f_ = NULL;
                other.callable_.reset();
            }

            // Writes the field value stored on the stack to the corresponding field of this function object.
            {
                LockScope<typename std::decay<decltype(*this)>::type> scope(*this);
                this->f_ = left_f;
                this->callable_ = left_callable;
            }
        }

    private:
        class ICallable {
        public:
            ICallable() = default;
            virtual ~ICallable() noexcept {}

        public:
            virtual R Invoke(Args & amp; & amp;... args) const = 0;
        };

        template <typename F>
        class Callable : public ICallable {
        public:
            Callable(const F & amp; f) noexcept : f_(f) {}
            Callable(F & amp; & amp; f) noexcept : f_(std::forward<F>(f)) {}
            virtual ~Callable() noexcept {}

        public:
            virtual R Invoke(Args & amp; & amp;... args) const override {
                if constexpr (std::is_same<R, void>::value) { /* sizeof...(args) */
                    f_(std::forward<Args>(args)...);
                }
                else {
                    return f_(std::forward<Args>(args)...); /* return R{}; */
                }
            }

        private:
            mutable F f_;
        };

        template <typename T>
        class LockScope {
        public:
            LockScope(T & obj) noexcept
                : obj_(obj) {
                obj_.lock();
            }
            ~LockScope() noexcept {
                obj_.unlock();
            }

        private:
            T & obj_;
        };

    private:
        mutable std::atomic<bool>lk_ = false;
        mutable Function f_ = NULL;
        mutable std::shared_ptr<ICallable> callable_ = NULL; // COW.
    };

    template <class F>
    inline bool operator==(const function<F> & amp; other, std::nullptr_t) noexcept {
        return !other;
    }

    template <class F>
    inline bool operator==(std::nullptr_t, const function<F> & amp; other) noexcept {
        return !other;
    }

    template <class F>
    inline bool operator!=(const function<F> & amp; other, std::nullptr_t) noexcept {
        return static_cast<bool>(other);
    }

    template <class F>
    inline bool operator!=(std::nullptr_t, const function<F> & amp; other) noexcept {
        return static_cast<bool>(other);
    }