首页 > 解决方案 > C ++ Lambda谓词原因变量不能在没有指定捕获默认值的lambda中隐式捕获

问题描述

这是函数定义

    template<typename Iter, typename T>
Iter lower_bound(Iter left, Iter right, const T& value){
    while (left < right){
        auto mid = std::next(left, std::distance(left, right)/2);
        if (*mid < value){
            left = std::next(mid);
        }else{
            right = mid;
        }

    }
    return left;
}



    template<typename Iter, typename T, typename Predicate>
Iter binary_search2(Iter left, Iter right, const T& value, Predicate funct){
    auto it = my::lower_bound(left, right, value);
    if (it != right && funct(*it)){
        return it;
    }else{
        return right;
    }
}

函数应该类似于 {return *it == value}; 所以我想我会在 main 方法中使用一个 lambda 函数,如下所示:

 auto searchValue = 10;

int comparisons = 0;  // see how many comparison made

auto iter = my::binary_search2(std::begin(data), std::end(data), searchValue, [&comparisons](int& num){
++comparisons;
return num == searchValue;

});

我收到一个奇怪的错误“无法在未指定捕获默认值的 lambda 中隐式捕获 searchValue”

有任何想法吗?

标签: c++lambda

解决方案


想想像这样的 lambda

auto x = [](int a) -> int {
    return a + 2;
};

就像

struct Lambda {
   int operator()(int a) const{
       return a + 2;
   }
};

这里

x(1) == Lambda{}(1) // == 3

现在,如果想从 lambda 上下文之外捕获一个额外的变量:

int y = 5;
auto x = [y](int a) -> int {
    return a + y;
};

这大致相当于

struct Lambda {
    explicit Lambda2(int y): y(y){}
    int operator()(int a) const{
        return a + y;
    }
    private:
    int y;
};

因此,现在

x(1) == Lambda{y} // == 6

第二种情况是所谓的捕获 Lambda,因为,嗯……它从其范围之外捕获变量。需要为 lambda(或大致等效的结构)提供它需要捕获的变量列表,以供以后调用时使用。

有很多方法可以捕获变量。对于您的问题,一种方法可能是按值捕获变量,因为它是一个普通整数

auto iter = my::binary_search2(std::begin(data), std::end(data), searchValue, 
    [&comparisons, searchValue](int& num){
    ++comparisons;
    return num == searchValue;
});

searchValue传递变量的副本。这有点像第二个版本的struct Lambda使用方式。

另一种方法是通过引用来捕获它,以防searchValue一个具有昂贵副本的变量或者想要在 lambda 主体中修改它。[这大致相当于传入了对构造函数的引用struct Lambda]

auto iter = my::binary_search2(std::begin(data), std::end(data), searchValue, 
    [&comparisons, &searchValue](int& num){
    ++comparisons;
    return num == searchValue;
});

如果您想通过引用捕获但不希望在 lambda 主体中对其进行修改,那么可以执行类似的操作

auto iter = my::binary_search2(std::begin(data), std::end(data), searchValue, 
    [&comparisons, &constSV = std::as_const(searchValue)](int& num){
    ++comparisons;
    return num == constSV;
});

通过使用std::as_const来获取对捕获变量的 const 引用。这相当于将 a 传递const&给 的构造函数struct Lambda

这些是一些可以使用的捕获类型。


推荐阅读