使用lambda作为参数:std::function还是模板?

5

我正在学习c++11,特别关注lambda表达式。

经过一些实践,我认为lambda闭包是一个无名函数对象。

于是我写了这段代码。

template <class callable_object>
void lambda_caller( callable_object lambda )
{
    std::cout<< sizeof(lambda) << endl;
    lambda();
}

我知道我可以使用std::function来代替使用模板,但我不想在类型转换时产生额外的开销。
但是我在阅读以下问题时发现了一个问题:为什么我不能在C++11中创建lambda向量? 回答者说,“每个lambda都有不同的类型-即使它们具有相同的签名。”
编译器为不同的类制作不同的代码。
因此,我认为每当我定义另一个lambda才能通过时,我的编译器将会创建另一个版本的lambda_caller
除了使用std::function之外,还有什么方法可以避免这种情况吗?是否有任何通用类型适用于lambda闭包?

2
std::function 不就是专门为此而设计的吗?您可以编写自己的包装器,为 lambda 提供相同的对象类型,并允许您透明地调用绑定到它的任何不同 lambda。如果您编写了一个好的实现,最终会得到 std::function(或类似的东西)。 - utnapistim
3
如果您只想使用任何可调用对象,可以使用模板,它还可以更轻松地进行内联。如果您希望存储它,则仍然可以使用模板,并在内部转换为std::function。而std::function的作用是用于存储可调用对象。 - Xeo
我之前不知道packaged_task。当我不想(或不需要)将我的类或函数转换为functor/lambda类型的模板时,我使用std::function作为输入参数(回调、事件通知接收器、错误处理策略等)。 - utnapistim
1
除非实现决定诉诸深度魔法,否则在这里使用std::function通常不会为您节省任何东西(除了在运行时更麻烦和昂贵之外):典型的实现将具有模板构造函数,因此不同的函数对象类型将产生该构造函数的不同实例化。很可能还会有更多内部模板机制实例化。您现在拥有的代码是最小的--几乎没有什么需要更改的。 - Luc Danton
2个回答

5

你无法避免它。Lambda只是一个带有operator()()重载的类,用于执行你的代码。因此,不同的代码对应不同的类。


0

std::function是lambda闭包的通用类型。问题在于每个lambda可能捕获不同的变量。因此,它不能简化为函数指针和一些数据,因为lambda可能捕获了3个变量或者4个变量。std::function将确保为数据分配足够的内存,但这是有代价的(数据可能会被堆分配)。

然而,如果您想要存储多个lambda,并且在编译时知道有多少个,您可以将它们存储在std::tuple中。这允许每个lambda具有不同的类型。不幸的是,C++仍然没有提供一种遍历元组的方法,但使用Boost.Fusion可以实现。


C++ 提供了一种方式——我只缺少 109 个字符就能在此评论中发布一个完整的示例 - Yakk - Adam Nevraumont
@Yakk 非常酷。当然,我并不是说这是不可能的,只是标准的C++库没有提供一种方法。 - Paul Fultz II
std::function是lambda闭包的通用类型。”我认为这个说法要么不正确,要么至少是误导性的:https://dev59.com/UloV5IYBdhLWcg3wmP3p#36030880。 - CrepeGoat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接