背景
现在手头主负责的服务代码,基本上都用C++11来开发了,异步编程使用的是TAF的future/promise。
future的then函数,接受的是一个Callback对象,该对象通过promise::bind来生成。
Callback和bind是参考chromium的base::Callback,base::Bind实现的,该版本并不支持C++11,所以bind() 不接受 lambda 作为 Currying 的载体(Currying ,译为柯里化是把接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术)。
使用TAF的promise进行异步编程,如果能够使用lambda表达式来完成回调,代码将更加清晰直观。
由于TAF的bind不接受 lambda表达式,因此回调有以下两种直观的方案:
方案1:使用独立的函数来产生 Callback
优点是,直观明确而且很传统不容易出错;
缺点是,对于代码量少的回调函数,要单独写一个函数,造成阅读代码时的上下文割裂。
方案2:使用 non-capturing lambda,自己手动 cast 到函数指针
优点是,代码连贯,可读性好,不需要专门去写一个函数,编码方便;
缺点是,而且手动 cast 非常的冗长繁琐。
于是对方案2进行了一些改进,通过template来对lambda表达式进行traits,将 non-capturing lambda 自动转换为等价的函数指针。
萃取lambda表达式
lambda其实是个C++对象(函数对象),只不过里面包含int operator()(int a,int b)之类的成员函数,从而可以被当做函数来使用,因此lambda表达式被当做参数来传递时,其实是传递的C++对象。
借助模板的神力、我们可以将lambda表达式的函数类型给萃取(traits)出来:
#include <iostream>
#include <typeinfo>
#include <tuple>
#include <type_traits>
namespace stx
{
namespace lambda_detail
{
// 将是否is_mutable、返回类型、参数包中元素个数、参数类型萃取出来
template<class Ret, class Cls, class IsMutable, class... Args>
struct types
{
using is_mutable = IsMutable;
enum { arity = sizeof...(Args) };
using return_type = Ret;