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

时间:2013-09-05 10:18:19

标签: c++ c++11 lambda delegates std-function

我正在尝试创建Don Clugston's Member Function Pointers and the Fastest Possible C++ Delegates的C ++ 11实现,并使其作为插入式std::function替换。

This is what I got so far.

我像这样构建lambda FastDelegates:

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

现在,一些测试:

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!

正如您所看到的,当lambda是“平凡的”(没有捕获)时,按值复制并获取其地址是有效的。但是当lambda存储某种状态(捕获)时,我不能只将它按值复制到FastFunc

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

我必须以某种方式存储 FastFunc内的lambda,但我不想使用std::shared_ptr,因为它很慢(I tried a different fastdelegate implementation that used it, and its performance was comparable to std::function)。< / p>

如何让我实施Don Clugston最快的C ++代表使用捕获状态的lambda,保留fastdelegates的惊人性能?

4 个答案:

答案 0 :(得分: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;

现在你可以(根据需要使用reinterpret_cast)将lambda存储在storage内,只要其大小合适(可以使用static_assert检测到)。

最后设法得到一个工作示例(必须从头重新启动,因为上帝是快速代理代码详细!!),你可以see it in action here(代码如下)。

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

代码:

#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;
}

答案 1 :(得分:1)

你不能。

这就是事情。 Fastdelegates仅适用于极少数非常具体的情况。这就是它变得更快的原因。您不会打败标准库实现者来实现std::function

答案 2 :(得分:1)

我已经制定了一个解决方案,将lambda函数作为指针只用于FastDelegate(它不存储任何其他东西)使用苦力和其他一些线程,例如:Get lambda parameter type

这里是:

namespace details{

    template<class FPtr> struct function_traits;
    template<class RT, class CT                                                                                        >struct function_traits<RT (CT::*)(                                      )     >{ typedef RT Result;                                                                                                                                                                  typedef RT (CT::*Signature)(                                      );};
    template<class RT, class CT                                                                                        >struct function_traits<RT (CT::*)(                                      )const>{ typedef RT Result;                                                                                                                                                                  typedef RT (CT::*Signature)(                                      );};
    template<class RT                                                                                                  >struct function_traits<RT        (                                      )     >{ typedef RT Result;                                                                                                                                                                  typedef RT       Signature (                                      );};
    template<class RT, class CT, class P1T                                                                             >struct function_traits<RT (CT::*)(P1T                                   )     >{ typedef RT Result;  typedef P1T Param1;                                                                                                                                             typedef RT (CT::*Signature)(P1T                                   );};
    template<class RT, class CT, class P1T                                                                             >struct function_traits<RT (CT::*)(P1T                                   )const>{ typedef RT Result;  typedef P1T Param1;                                                                                                                                             typedef RT (CT::*Signature)(P1T                                   );};
    template<class RT          , class P1T                                                                             >struct function_traits<RT        (P1T                                   )     >{ typedef RT Result;  typedef P1T Param1;                                                                                                                                             typedef RT       Signature (P1T                                   );};
    template<class RT, class CT, class P1T, class P2T                                                                  >struct function_traits<RT (CT::*)(P1T, P2T                              )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2;                                                                                                                         typedef RT (CT::*Signature)(P1T, P2T                              );};
    template<class RT, class CT, class P1T, class P2T                                                                  >struct function_traits<RT (CT::*)(P1T, P2T                              )const>{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2;                                                                                                                         typedef RT (CT::*Signature)(P1T, P2T                              );};
    template<class RT          , class P1T, class P2T                                                                  >struct function_traits<RT        (P1T, P2T                              )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2;                                                                                                                         typedef RT       Signature (P1T, P2T                              );};
    template<class RT, class CT, class P1T, class P2T, class P3T                                                       >struct function_traits<RT (CT::*)(P1T, P2T, P3T                         )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3;                                                                                                     typedef RT (CT::*Signature)(P1T, P2T, P3T                         );};
    template<class RT, class CT, class P1T, class P2T, class P3T                                                       >struct function_traits<RT (CT::*)(P1T, P2T, P3T                         )const>{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3;                                                                                                     typedef RT (CT::*Signature)(P1T, P2T, P3T                         );};
    template<class RT          , class P1T, class P2T, class P3T                                                       >struct function_traits<RT        (P1T, P2T, P3T                         )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3;                                                                                                     typedef RT       Signature (P1T, P2T, P3T                         );};
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T                                            >struct function_traits<RT (CT::*)(P1T, P2T, P3T, P4T                    )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4;                                                                                 typedef RT (CT::*Signature)(P1T, P2T, P3T, P4T                    );};
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T                                            >struct function_traits<RT (CT::*)(P1T, P2T, P3T, P4T                    )const>{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4;                                                                                 typedef RT (CT::*Signature)(P1T, P2T, P3T, P4T                    );};
    template<class RT          , class P1T, class P2T, class P3T, class P4T                                            >struct function_traits<RT        (P1T, P2T, P3T, P4T                    )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4;                                                                                 typedef RT       Signature (P1T, P2T, P3T, P4T                    );};
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T                                 >struct function_traits<RT (CT::*)(P1T, P2T, P3T, P4T, P5T               )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5;                                                             typedef RT (CT::*Signature)(P1T, P2T, P3T, P4T, P5T               );};
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T                                 >struct function_traits<RT (CT::*)(P1T, P2T, P3T, P4T, P5T               )const>{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5;                                                             typedef RT (CT::*Signature)(P1T, P2T, P3T, P4T, P5T               );};
    template<class RT          , class P1T, class P2T, class P3T, class P4T, class P5T                                 >struct function_traits<RT        (P1T, P2T, P3T, P4T, P5T               )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5;                                                             typedef RT       Signature (P1T, P2T, P3T, P4T, P5T               );};
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T                      >struct function_traits<RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T          )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5; typedef P6T Param6;                                         typedef RT (CT::*Signature)(P1T, P2T, P3T, P4T, P5T, P6T          );};
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T                      >struct function_traits<RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T          )const>{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5; typedef P6T Param6;                                         typedef RT (CT::*Signature)(P1T, P2T, P3T, P4T, P5T, P6T          );};
    template<class RT          , class P1T, class P2T, class P3T, class P4T, class P5T, class P6T                      >struct function_traits<RT        (P1T, P2T, P3T, P4T, P5T, P6T          )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5; typedef P6T Param6;                                         typedef RT       Signature (P1T, P2T, P3T, P4T, P5T, P6T          );};
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T           >struct function_traits<RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T, P7T     )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5; typedef P6T Param6; typedef P7T Param7;                     typedef RT (CT::*Signature)(P1T, P2T, P3T, P4T, P5T, P6T, P7T     );};
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T           >struct function_traits<RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T, P7T     )const>{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5; typedef P6T Param6; typedef P7T Param7;                     typedef RT (CT::*Signature)(P1T, P2T, P3T, P4T, P5T, P6T, P7T     );};
    template<class RT          , class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T           >struct function_traits<RT        (P1T, P2T, P3T, P4T, P5T, P6T, P7T     )     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5; typedef P6T Param6; typedef P7T Param7;                     typedef RT       Signature (P1T, P2T, P3T, P4T, P5T, P6T, P7T     );};
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T, class P8T>struct function_traits<RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T)     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5; typedef P6T Param6; typedef P7T Param7; typedef P8T Param8; typedef RT (CT::*Signature)(P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T);};
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T, class P8T>struct function_traits<RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T)const>{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5; typedef P6T Param6; typedef P7T Param7; typedef P8T Param8; typedef RT (CT::*Signature)(P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T);};
    template<class RT          , class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T, class P8T>struct function_traits<RT        (P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T)     >{ typedef RT Result;  typedef P1T Param1; typedef P2T Param2; typedef P3T Param3; typedef P4T Param4; typedef P5T Param5; typedef P6T Param6; typedef P7T Param7; typedef P8T Param8; typedef RT       Signature (P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T);};

    template<class T>
    typename function_traits<T>::Signature* bar_helper(T);

    template<class F>
    class FuncTraitsOf{
    public:
        typedef decltype(bar_helper(&F::operator())) fptr;
        typedef typename std::remove_pointer<fptr>::type Signature;     //Signature =   bool __cdecl(int,float)
        typedef typename function_traits< Signature > R;                //R         =   struct function_traits<bool __cdecl(int,float)>
    };

    template< class FuncTraits>class FDSel;
    template<class RT, class CT                                                                                        > struct FDSel< function_traits< RT (CT::*)(                                      )      > >{ typedef fastdelegate::FastDelegate0<                                       RT> R; };
    template<class RT, class CT                                                                                        > struct FDSel< function_traits< RT (CT::*)(                                      )const > >{ typedef fastdelegate::FastDelegate0<                                       RT> R; };
    template<class RT                                                                                                  > struct FDSel< function_traits< RT        (                                      )      > >{ typedef fastdelegate::FastDelegate0<                                       RT> R; };
    template<class RT, class CT, class P1T                                                                             > struct FDSel< function_traits< RT (CT::*)(P1T                                   )      > >{ typedef fastdelegate::FastDelegate1<P1T                                   ,RT> R; };
    template<class RT, class CT, class P1T                                                                             > struct FDSel< function_traits< RT (CT::*)(P1T                                   )const > >{ typedef fastdelegate::FastDelegate1<P1T                                   ,RT> R; };
    template<class RT          , class P1T                                                                             > struct FDSel< function_traits< RT        (P1T                                   )      > >{ typedef fastdelegate::FastDelegate1<P1T                                   ,RT> R; };
    template<class RT, class CT, class P1T, class P2T                                                                  > struct FDSel< function_traits< RT (CT::*)(P1T, P2T                              )      > >{ typedef fastdelegate::FastDelegate2<P1T, P2T                              ,RT> R; };
    template<class RT, class CT, class P1T, class P2T                                                                  > struct FDSel< function_traits< RT (CT::*)(P1T, P2T                              )const > >{ typedef fastdelegate::FastDelegate2<P1T, P2T                              ,RT> R; };
    template<class RT          , class P1T, class P2T                                                                  > struct FDSel< function_traits< RT        (P1T, P2T                              )      > >{ typedef fastdelegate::FastDelegate2<P1T, P2T                              ,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T                                                       > struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T                         )      > >{ typedef fastdelegate::FastDelegate3<P1T, P2T, P3T                         ,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T                                                       > struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T                         )const > >{ typedef fastdelegate::FastDelegate3<P1T, P2T, P3T                         ,RT> R; };
    template<class RT          , class P1T, class P2T, class P3T                                                       > struct FDSel< function_traits< RT        (P1T, P2T, P3T                         )      > >{ typedef fastdelegate::FastDelegate3<P1T, P2T, P3T                         ,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T                                            > struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T, P4T                    )      > >{ typedef fastdelegate::FastDelegate4<P1T, P2T, P3T, P4T                    ,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T                                            > struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T, P4T                    )const > >{ typedef fastdelegate::FastDelegate4<P1T, P2T, P3T, P4T                    ,RT> R; };
    template<class RT          , class P1T, class P2T, class P3T, class P4T                                            > struct FDSel< function_traits< RT        (P1T, P2T, P3T, P4T                    )      > >{ typedef fastdelegate::FastDelegate4<P1T, P2T, P3T, P4T                    ,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T                                 > struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T, P4T, P5T               )      > >{ typedef fastdelegate::FastDelegate5<P1T, P2T, P3T, P4T, P5T               ,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T                                 > struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T, P4T, P5T               )const > >{ typedef fastdelegate::FastDelegate5<P1T, P2T, P3T, P4T, P5T               ,RT> R; };
    template<class RT          , class P1T, class P2T, class P3T, class P4T, class P5T                                 > struct FDSel< function_traits< RT        (P1T, P2T, P3T, P4T, P5T               )      > >{ typedef fastdelegate::FastDelegate5<P1T, P2T, P3T, P4T, P5T               ,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T                      > struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T          )      > >{ typedef fastdelegate::FastDelegate6<P1T, P2T, P3T, P4T, P5T, P6T          ,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T                      > struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T          )const > >{ typedef fastdelegate::FastDelegate6<P1T, P2T, P3T, P4T, P5T, P6T          ,RT> R; };
    template<class RT          , class P1T, class P2T, class P3T, class P4T, class P5T, class P6T                      > struct FDSel< function_traits< RT        (P1T, P2T, P3T, P4T, P5T, P6T          )      > >{ typedef fastdelegate::FastDelegate6<P1T, P2T, P3T, P4T, P5T, P6T          ,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T           > struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T, P7T     )      > >{ typedef fastdelegate::FastDelegate7<P1T, P2T, P3T, P4T, P5T, P6T, P7T     ,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T           > struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T, P7T     )const > >{ typedef fastdelegate::FastDelegate7<P1T, P2T, P3T, P4T, P5T, P6T, P7T     ,RT> R; };
    template<class RT          , class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T           > struct FDSel< function_traits< RT        (P1T, P2T, P3T, P4T, P5T, P6T, P7T     )      > >{ typedef fastdelegate::FastDelegate7<P1T, P2T, P3T, P4T, P5T, P6T, P7T     ,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T, class P8T> struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T)      > >{ typedef fastdelegate::FastDelegate8<P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T,RT> R; };
    template<class RT, class CT, class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T, class P8T> struct FDSel< function_traits< RT (CT::*)(P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T)const > >{ typedef fastdelegate::FastDelegate8<P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T,RT> R; };
    template<class RT          , class P1T, class P2T, class P3T, class P4T, class P5T, class P6T, class P7T, class P8T> struct FDSel< function_traits< RT        (P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T)      > >{ typedef fastdelegate::FastDelegate8<P1T, P2T, P3T, P4T, P5T, P6T, P7T, P8T,RT> R; };


}


template<class F>
typename details::FDSel< typename details::FuncTraitsOf<F>::R >::R MakeDelegate(F& f){
    return fastdelegate::MakeDelegate(&f, &F::operator());
}

将其复制/粘贴到FastDelegate.h文件中。

不要像这样使用它:

home.visit(fastdelegate::MakeDelegate([&](const Room& a){ /* ... */ }));

而是这样做:

auto d = [&](const Room& a){ /* ... */ };
home.visit(fastdelegate::MakeDelegate(d));

如果我错过了什么,请告诉我。

答案 3 :(得分:0)

“普通”和普通lambda函数之间的区别在于,如果它不属于第一个类(没有捕获),则它是一个函数对象。

如果复制对象(lambda)并且它包含对临时对象的引用,或者在FastDelegate被销毁之前将被释放的堆栈分配对象的引用,则会有一个悬空引用,因此崩溃。

尝试通过副本捕获,而不是通过引用