如何定义一个以捕获为参数的 lambda 的函数?

Posted

技术标签:

【中文标题】如何定义一个以捕获为参数的 lambda 的函数?【英文标题】:How can I define a function that takes a lambda with capture as parameter? 【发布时间】:2021-10-24 16:10:06 【问题描述】:

如果 list 中的任何元素与给定的predicate 匹配,我有这个函数返回true

bool _any(bool (*predicate)(MyStructure), list<MyStructure> arr)

    for (int i = 0; i < arr.size(); i++)
    
        if (predicate(arr.front()))
            return true;
        arr.pop_front();
    
    return false;

这适用于非常简单的 lambda,但如果给定的 lambda 需要捕获 this,那么我会遇到一个错误,我不知道如何修复。

Assert::IsTrue(_any(
    [this](MyStructure t)
    
        return t._name == "NAME_SEARCHED" &&
            t._type == "TYPE_SEARCHED" &&
            _any([](OtherStruct o)  return o._name == "SEARCHED_2"; , t._children);
    ,
    myList));

错误:

cannot convert argument 1 from 'UTests::<lambda_e8bda0383e9f0c2ae44be631a7424852>' 
to 'bool (__cdecl *)(MyNameSpace::MyStructure)'

(注:_any 也定义了 OtherStruct)。

【问题讨论】:

最简单的方法是使用std::function 或模板。 @JeJo 确实,从那时起我就解决了这个问题。我今天刚刚深入研究了 C++(我有很强的 C# 背景),这主要是复制/粘贴的东西,我稍后会复习/增强。关键是确保基础工作正常。 【参考方案1】:

您不能将有状态的 lambda 转换为函数指针!

问题是,_any 函数需要 bool (*)(MyStructure) 类型的类型化 函数指针 不是 lambda 函数。你可以将 lambda 转换为函数指针,如果它是一个无捕获的 lambda。

也就是说,这里

Assert::IsTrue(_any(
[this](MyStructure t)
//^^^^ ---> capture the "this"

   // ...
,
myList));

您正在尝试将 lambda 函数(通过捕获实例)转换为 typed function pointer。 这根本不可能,因此会出现编译器错误。


我不知道如何解决。

_any设为模板函数,以便编译器为你做推演。

template<typename Callable>
bool _any(Callable predicate, std::list<MyStructure> const& arr)

   // ...
    return false;

或使用std::function、with some type erasure overhead

#include <functional> // std::function

bool _any(std::function<bool(MyStructure)> const& predicate
    , std::list<MyStructure> const& arr)

   // ...
    return false;

【讨论】:

我实际上选择了std::function&lt;bool(MyStructure)&gt; predicate,我猜是一样的,但我相信这也是一个可行的解决方案。两者有什么区别? 值得注意的是,如果你不介意几层抽象,你可以不用模板或std::function【参考方案2】:

只需使用 std::for_each() 中的模板参数即可。

顺便说一句,我不确定按值传递列表并使用它是必要的。

template<typename Predicate>
bool _any(Predicate predicate, const list<MyStructure> &arr)

    for(const auto &elem: arr)
    
        if (predicate(elem))
            return true;
    
    return false;

最后,您可以依赖std::any_of()

template<typename Predicate>
bool _any(Predicate predicate, const list<MyStructure> &arr)

    return std::any_of(cbegin(arr), cend(arr), predicate);

看看&lt;algorithm&gt; 的现有功能,几乎“一切”都已经存在,并且可以适应特定的上下文,这要归功于预期作为模板参数的 lambda-closures

一般来说,std::function 应该只在需要存储闭包以便稍后调用(线程、回调...)时使用。 如果闭包直接在函数中使用,并且函数返回时不再需要存在,那么模板方案是首选,因为它节省了一点内存和效率。

【讨论】:

以上是关于如何定义一个以捕获为参数的 lambda 的函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用lambda表达式捕获局部变量?

c ++ lambdas如何从上层范围捕获可变参数包

Lambda表达式的使用

如何使用 C++ lambda 将成员函数指针转换为普通函数指针以用作回调

如何定义 Lambda 变量以通过 API Gateway 查询 Redshift

使用lambda函数进行向量排序,当不在同一范围内时如何传递变量来捕获组?