FastDelegate 和 lambda - 无法让它们工作(Don Clugston 最快的可能代表)

FastDelegate and lambdas - can't get them to work (Don Clugston's fastest possible delegates)

本文关键字:Clugston Don lambda 工作 FastDelegate      更新时间:2023-10-16

我正在尝试创建Don Clugston的成员函数指针和最快的C++委托的C++11实现,并使其作为直接std::function替代品。

这就是我到目前为止得到的。

我像这样构造 lambda FastDelegate:

// 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,但是当它是临时的时,我无法做到这一点,就像示例中一样。

我必须以某种方式将lambda存储在FastFunc中,但我不想使用std::shared_ptr因为它很慢(我尝试了使用它的不同fastdelegate实现,其性能与std::function相当)。

如何使 Don Clugston 的最快可能C++委托的实现与捕获状态的 lambda 一起工作,从而保留快速委托的惊人性能?

您已经很好地诊断了情况:您需要存储状态。

由于 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 检测到)。

最后设法得到了一个工作示例(必须从头开始,因为上帝是那么快速的委托代码冗长!!

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

法典:

#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 << "statelessn"; };
    stateless();
    bool b = true;
    FastFunc<void(), 32> stateful = [&b]() { std::cout << "stateful: " << b << "n"; };
    stateful();
    b = false;
    stateful();
    return 0;
}

你不能。

事情是这样的。快速委托仅适用于极少数非常特殊的情况。这就是使它更快的原因。您不会在实现std::function方面击败您的标准库实施者。

我提出了一个解决方案,使用艰苦的劳动和其他几个线程将 lambda 函数作为指针仅放入 FastDelegate(它不存储任何其他内容),例如: 获取 lambda 参数类型

在这里:

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));

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

"平凡"函数和一般 lambda 函数之间的区别在于,如果它不属于第一个类(没有捕获),它就是一个函数对象。

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

尝试通过复制而不是引用捕获