我正在尝试创建Don Clugston's Member Function Pointers and the Fastest Possible C++ Delegates的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());
}
现在,一些测试:
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的惊人性能?
答案 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被销毁之前将被释放的堆栈分配对象的引用,则会有一个悬空引用,因此崩溃。
尝试通过副本捕获,而不是通过引用