Function wrapper like std::function that uses "small buffer" allocation My Function class is similar to std::function with the small-buffer optimization. However, it always uses  a small buffer and static asserts if the required size exceeds it.

I would like a review for:


correct use of the low-level features
general class design and interoperability with standard library


Here is my code:

#include &lt;cassert&gt;
#include &lt;functional&gt;
#include &lt;iostream&gt;
#include &lt;new&gt;
#include &lt;utility&gt;
#include &lt;array&gt;


template&lt;typename Signature&gt;
struct Function;

template&lt;typename R, typename ...Args&gt;
struct Function&lt;R(Args...)&gt;
{
    Function() : storage()
    {}

    template&lt;typename F&gt;
    Function(const F&amp; f)
    {
        static_assert(alignof(F) &lt;= alignof(Function), "");
        static_assert(sizeof(f) &lt;= sizeof(storage), "");

        new (storage.data()) Impl&lt;F&gt;(f);
    }

    Function(const Function&amp; rhs) : 
        storage(rhs.storage)
    {
        if (rhs.valid())
        {
            rhs.getImpl().clone(data());
        }
    }

    Function(Function&amp;&amp; rhs) noexcept :
        storage(rhs.storage)
    {
        rhs.storage = Storage();
    }

    Function&amp; operator=(Function rhs) noexcept
    {
        std::swap(storage, rhs.storage); // not sure if safe
        return *this;
    }

    ~Function()
    {
        if (valid())
        {
            getImpl().~Base();
        }
    }

    R operator()(Args&amp;&amp; ...args) const
    {
        if (!valid())
        {
            throw std::bad_function_call();
        }
        return getImpl().call(std::forward&lt;Args&gt;(args)...);
    }

private:
    struct Base
    {
        virtual ~Base() {}
        virtual R call(Args&amp;&amp; ...args) const = 0;
        virtual void clone(void* where) const = 0;
    };


    template&lt;typename F&gt;
    struct Impl : Base
    {
        Impl(const F&amp; f) : f(f) {}

        R call(Args&amp;&amp; ...args) const override final
        { return f(std::forward&lt;Args&gt;(args)...); }

        void clone(void* where) const override final
        { new (where) Impl&lt;F&gt;(*this); }

        F f;
    };

    // convenience methods
    bool valid() const
    { return storage != Storage(); }

    const void* data() const
    { return static_cast&lt;const void*&gt;(storage.data()); }

    void* data()
    { return static_cast&lt;void*&gt;(storage.data()); }

    const Base&amp; getImpl() const
    { assert(valid()); return *static_cast&lt;const Base*&gt;(data()); }

    Base&amp; getImpl()
    { assert(valid()); return *static_cast&lt;Base*&gt;(data()); }

    typedef std::array&lt;long, 4&gt; Storage; // long is probably max-align
    Storage storage;
};


int main()
{
    Function&lt;int(int)&gt; increment = [](int n) {
        return n + 1;
    };
    Function&lt;int(int)&gt; decrement = [](int n) {
        return n - 1;
    };


    std::cout &lt;&lt; increment(3) &lt;&lt; std::endl;    
    std::cout &lt;&lt; decrement(3) &lt;&lt; std::endl;

    increment = std::move(decrement);
    std::cout &lt;&lt; increment(3) &lt;&lt; std::endl;


    // calling the moved-from decrement
    try
    {
        decrement(3);
        assert(false);
    }
    catch (std::bad_function_call&amp; e)
    {
        std::cout &lt;&lt; e.what() &lt;&lt; std::endl;
    }
}
Generally, I can't see any real problems, but there are a few things that I'm going to point out:

In the assignment operator, you use std::swap(storage, rhs.storage) and declare it as noexcept. This should probably be conditionally noexcept, based on whether the swap implementation for the given array type (in this case, array&lt;long&gt;) is noexcept. That being said, I'd be really, really surprised if this wasn't always true.

The only other issues I can see are to do with alignment and storage size, which you've basically dealt with thanks to the two static_asserts in the constructor for Function (although they should both have a string detailing exactly what happened if either of them fails). As you're probably aware, there are precious few guarantees about function pointer sizes (especially when you start dealing with a combination of member functions, virtual functions, and multiple inheritance). 4 * sizeof(long) should be enough space to hold anything like this, but this is implementation defined; there are no guarantees.

With regards to alignment, I'm less confident. long is only guaranteed by the standard to be at least 4 bytes, and this is true even for 64-bit platforms. Since storage is actually holding the function itself, the alignment should be made more explicit, and shouldn't rely on the (potentially less stringent) alignment of long. I'd personally suggest:

alignas(std::intptr_t) Storage storage;


which (as far as I can see) should ensure storage will be aligned on the correct boundary.