C++ FastDelegate和lambdas-can';不要让他们工作(Don Clugston&最快的代表)
我正在尝试创建的C++11实现,并将其作为一个插入式C++ FastDelegate和lambdas-can';不要让他们工作(Don Clugston&最快的代表),c++,c++11,lambda,delegates,std-function,C++,C++11,Lambda,Delegates,Std Function,我正在尝试创建的C++11实现,并将其作为一个插入式std::function替换 我这样构造lambda FastDelegate: // FastFunc is my name for FastDelegate template<typename LambdaType> FastFunc(LambdaType lambdaExpression) { this->m_Closure.bindmemfunc(&lambdaExpression, &La
std::function
替换
我这样构造lambda FastDelegate:
// FastFunc is my name for FastDelegate
template<typename LambdaType> FastFunc(LambdaType lambdaExpression)
{
this->m_Closure.bindmemfunc(&lambdaExpression, &LambdaType::operator());
}
home.visit(fastdelegate::MakeDelegate([&](const Room& a){ /* ... */ }));
//FastFunc是我对FastDelegate的名字
模板FastFunc(LambdaType lambdaExpression)
{
这->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!
FastFunc test=[]{std::cout普通lambda函数和普通lambda函数之间的区别在于,如果它不属于第一类(无捕获),那么它就是一个函数对象
如果复制对象(lambda),并且该对象包含对临时对象的引用,或者对将在FastDelegate销毁之前释放的堆栈分配对象的引用,则会出现悬空引用,从而导致崩溃
尝试通过复制而不是引用捕获您已经很好地诊断了这种情况:您需要存储状态
由于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;
你不能
事情是这样的。FastDelegate只适用于极少数非常特殊的情况。这就是它的速度。在实现std::function
时,你不会打败标准库实现者。我已经提出了一个解决方案,只将lambda函数作为指针安装到FastDelegate中(它不存储任何其他内容)使用体力劳动和一些其他线程,例如:
这是:
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());
}
而是这样做:
auto d = [&](const Room& a){ /* ... */ };
home.visit(fastdelegate::MakeDelegate(d));
如果我遗漏了什么,请告诉我。这是因为您无法将捕获的lambda转换为函数指针:您需要类型擦除,并且std::shared\u ptr
提供它。@user1095108:如果您复制一个std::function
封装可变lambda(也称为具有可变状态的lambda)两个std::function
实例是否共享相同的状态,或者每个实例都有自己的副本?@MatthieuM。每个实例都有自己的副本。@user1095108:好的,那么它可能不使用std::shared_ptr
,因为类型擦除会阻止复制内部lambda(没有clone
方法)@MatthieuM.No,它使用放置new
或复制到new
ly分配的块中。关于可变项hehehe,这一点很好。您的解释是正确的,但这一点是在std::function
中具有更快的插入速度,而不是更改现有的lambda代码。std::function
在lambda c的示例中起作用通过引用使用bool
,但速度很慢。我的目标是使用Don Clugston工作背后的概念创建一个更快版本的std::function
@Vittorio:你不会的。快速委托只在std::function可以工作的一小部分场景中有效。这就是为什么它更快。你不太可能打败y我们的标准库实现者。@DeadMG是的,但有时你可能不喜欢这个接口,然后你自己做东西。例如,我不喜欢使用std::bind
或带有std::function
的lambda对象来调用成员函数。@user1095108:除非他打算大规模限制他的接口,否则他仍然是一个使用与std::function相同的约束创建一个类,这几乎肯定会导致本质上相同的实现权衡,因此基本上相同的性能。@VittorioRomeo曾经问过自己,为什么实现std::function
的人没有使用Don Clugston工作背后的概念来创建更快的版本std::function
?std::aligned_storage
的版本听起来不错!但是,我在将lambda移动到存储中时遇到了问题。你能给出一个简单的例子吗?cppreference上的那些没有帮助。@VittorioRomeo只需将它复制或移动到那里,例如新建(&storage)LambdaType(lambdaExpression)
。但是它不会更快,因为存储
位置现在取决于这个
指针,这意味着现在就可以内联调用了impossible@VittorioRomeo当前位置我正在研究它,但那个快的代理上帝太可怕了,我从零开始做了一些简单的事情。我想它可能不再快了(并不意味着性能保证!),但它确实展示了如何复制/移动状态。这难道不等于重新实现std::function
(也包括虚拟函数!)?@R.MartinhoFernandes:好吧……这就是fast delegate的意义所在(尽管它是在std::function
不存在的时候发明的)。尽管有一些小的区别:1/std::function
使用堆分配(通常),因此这可能更快;2/它使用的空间比使用虚拟函数(可能)要少。对于虚拟函数,似乎需要同时存储虚拟指针(存储中)和指向基类的指针(存储外部).
auto d = [&](const Room& a){ /* ... */ };
home.visit(fastdelegate::MakeDelegate(d));