【问题标题】:No matching function error when passing lambda function as argument将 lambda 函数作为参数传递时没有匹配函数错误
【发布时间】:2015-09-29 09:22:59
【问题描述】:

我有一个数字列表。

我正在尝试过滤列表,只保留正数。

我试图通过传递一个 lambda 作为参数来做到这一点。

我想知道为什么会出现函数不匹配错误。

#include <vector>
#include <algorithm>
#include <functional>

template<typename T>
std::vector<T> keep(
        const std::vector<T> &original,
        std::function<bool(const T&)> useful)
{
    std::vector<T> out;
    for(T item:original)
    {
        if(useful(item))
            out.push_back(item);
    }
    return out;
}

int main()
{
    std::vector<int> a={4,6,2,-5,3,-8,13,-11,27};
    a=keep(a,[](const int& x)->bool{return x>0;});
    for(int y:a)
    {
        std::cout<<y<<std::endl;
    }
    return 0;
}

这是错误信息:

error: no matching function for call to ‘keep(std::vector<int>&, main()::<lambda(const int&)>)’
     a=keep(a,[](const int& x)->bool{return x>0;});
                                                 ^

【问题讨论】:

标签: c++ c++11 lambda type-conversion callable-object


【解决方案1】:

将函数keep改为

template<typename T, typename Func>
std::vector<T> keep(const std::vector<T> &original,
                    Func useful)
{
    // code as usual
}

Live example.

这适用于 useful 的参数是以下任何一个:

  • λ
  • std::function
  • functor
  • 函数指针

来自the documentation

lambda 表达式构造一个唯一的未命名非联合非聚合类型的未命名纯右值临时对象,称为闭包类型。

这意味着两个具有相同代码的 lambda 会生成两个不同类型的对象。

auto f1 = [](int) { return true; };
auto f2 = [](int) { return false; };
f2 = f1;                               // error: no viable '='

但是,这两者都可以隐式转换为相应的 std::function 类型:

std::function<bool(int)> fn = f1;
fn = f2;

但是为什么它在你的情况下不起作用?这是因为模板类型扣除。将keep 更改为

template<typename T>
std::vector<T> keep(const std::vector<T> &original,
                    std::function<bool(const int &)> useful)
// no type deduction for std::function's template, explicitly mentioned

将使您的示例在调用方站点上编译而无需任何转换。

但是,尝试将其与std::function&lt;T&gt; 匹配将不起作用,因为模板类型推导不考虑任何转换。模板参数推导查找精确的类型匹配。在这个阶段,隐式转换并不重要。您必须将其显式转换为匹配的 std::function 作为 Atomic_alarm cmets。正如约瑟夫在How to convert a lambda to an std::function using templates 中所说:

模板类型推导尝试将 lambda 函数的类型与 std::function&lt;T&gt; 匹配,在这种情况下它无法做到 - 这些类型不一样。模板类型推导不考虑类型之间的转换。

在替代解决方案中发生的情况是这样的:

auto f = [](int i) { return (i >= 0); }

这里的f 的类型不是std::function,而是一些未命名的类型,就像上面的模板参数Func 一样。

如果您仍想以std::function 的方式执行此操作,请参阅this answer,它使用额外的模板间接实现。相关详情见this answerthis post

【讨论】:

  • 谢谢。我仍然想知道我的代码有什么问题?我哪里做错了?
  • @ar2015,lambda 表达式有自己的类型,所以显式转换,或者使用模板。 IDEone:ideone.com/r2gYTh
  • @ar2015 详细原因现在在更新的答案中。
猜你喜欢
  • 2018-10-26
  • 2017-12-14
  • 1970-01-01
  • 2017-07-17
  • 1970-01-01
  • 2022-07-23
  • 1970-01-01
  • 2017-06-14
  • 2016-04-21
相关资源
最近更新 更多