FastDelegate和lambdas - 无法让他们工作(Don Clugston最快的代表)

Vit*_*meo 3 c++ lambda delegates c++11 std-function

我正在尝试创建Don Clugston的成员函数指针和最快可能的C++代表的C++ 11实现,并使其成为std::function替代品.

这是我到目前为止所得到的.

我像这样构造lambda FastDelegates:

// FastFunc is my name for FastDelegate
template<typename LambdaType> FastFunc(LambdaType lambdaExpression)
{
    this->m_Closure.bindmemfunc(&lambdaExpression, &LambdaType::operator());
}
Run Code Online (Sandbox Code Playgroud)

现在,一些测试:

FastFunc<void()> test = []{ std::cout << "hello" << std::endl; };
test();
// Correctly prints "hello"

bool b{false};
FastFunc<void()> test2 = [&b]{ std::cout << b << std::endl; };
test2();
// Crash!
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,当lambda是"微不足道的"(没有捕获)时,按值复制并获取其地址是有效的.但是当lambda存储某种状态(捕获)时,我不能只按值将其复制到FastFunc.

我尝试通过引用获取lambda,但是当它像示例中的临时时我不能这样做.

我必须以某种方式 lambda 存储在其中FastFunc,但我不想使用std::shared_ptr因为它很慢(我尝试了一个使用它的不同fastdelegate实现,并且它的性能可比std::function).

我怎样才能让我实现Don Clugston最快的C++代表与lambdas一起工作,捕获状态,保持fastdelegates的惊人表现?

Mat*_* M. 8

你已经很好地诊断出了这种状况:你需要存储状态.

由于lambda是一个临时对象,实际上允许你从它(通常)移动,如果可能的话,这应该是首选的(因为移动比复制更通用).

现在,您需要做的就是为它保留一些存储空间,如果这需要动态分配,您可能确实会降低性能.另一方面,物体需要有固定的足迹,所以?

一种可能的解决方案是提供可配置(但有限)的存储容量:

static size_t const Size = 32;
static size_t const Alignment = alignof(std::max_align_t);

typedef std::aligned_storage<Size, Alignment>::type Storage;
Storage storage;
Run Code Online (Sandbox Code Playgroud)

现在你可以(根据需要使用reinterpret_cast)将你的lambda存储在storage其大小适合的范围内(可以使用它来检测static_assert).

最后设法得到一个工作的例子(不得不从头重新开始,因为上帝是那个快速的委托代码详细!!),你可以在这里看到它(以及代码如下).

我只是划伤了表面,特别是因为它缺少复制和移动操作符.为了正确地执行这些操作,需要按照与其他两个操作相同的模式将这些操作添加到处理程序.

码:

#include <cstddef>

#include <iostream>
#include <memory>
#include <type_traits>

template <typename, size_t> class FastFunc;

template <typename R, typename... Args, size_t Size>
class FastFunc<R(Args...), Size> {
public:
    template <typename F>
    FastFunc(F f): handler(&Get<F>()) {
        new (&storage) F(std::move(f));
    }

    ~FastFunc() {
        handler->destroy(&storage);
    }

    R operator()(Args&&... args) {
      return handler->apply(&storage, std::forward<Args>(args)...);
    }

private:
    using Storage = typename std::aligned_storage<Size, alignof(max_align_t)>::type;

    struct Handler {
        R (*apply)(void*, Args&&...);
        void (*destroy)(void*);
    }; // struct Handler

    template <typename F>
    static R Apply(void* f, Args&&... args) {
        (*reinterpret_cast<F*>(f))(std::forward<Args>(args)...);
    }

    template <typename F>
    static void Destroy(void* f) {
        reinterpret_cast<F*>(f)->~F();
    }

    template <typename F>
    Handler const& Get() {
        static Handler const H = { &Apply<F>, &Destroy<F> };
        return H;
    } // Get

    Handler const* handler;
    Storage storage;
}; // class FastFunc

int main() {
    FastFunc<void(), 32> stateless = []() { std::cout << "stateless\n"; };
    stateless();

    bool b = true;
    FastFunc<void(), 32> stateful = [&b]() { std::cout << "stateful: " << b << "\n"; };
    stateful();

    b = false;
    stateful();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 这不等于重新实现`std :: function`(以及虚函数!)? (4认同)