首页 > 解决方案 > 通过参数传递 lambda(无函数类型模板)

问题描述

我想在此处不使用函数模板,而是使用std::function或类型化函数指针来传递 lambda。

#include <iostream>
#include <list>
#include <functional>

template<typename T>
std::list<T> mapll(std::function<T(T)> f, std::list<T> l) {
    for(auto it = l.begin(); it != l.end(); ++it) {
        *it = f(*it);
    }
}
int main() {
    // Make it
    std::list<int> l = std::list<int> {1,2,3};
    // Map it
    mapll([](int n) { return n * 2; }, l);
    // Print it
    std::cout << "{";
    for (auto it = l.begin(); it != l.end(); ++it) {
        if (it == l.begin())
            std::cout << "," << *it;
        std::cout << *it;
    }
} 

但我没有成功调用mapll. 错误是:

clang++ -g -DNDEBUG -std=c++17 -Wno-switch-bool -lc main.cpp -o main

main.cpp:51:2: error: no matching function for call to 'mapll'
        mapll([](int n) { return n * 2; }, l);

^~~~~ main.cpp:42:14: note: candidate template ignored: could not match 
'function<type-parameter-0-0 (type-parameter-0-0)>' against
    '(lambda at main.cpp:51:8)' std::list<T> mapll(std::function<T(T)> f, std::list<T> l) {

标签: c++lambdafunction-pointersc++17

解决方案


没有推导出std::function参数,因为 lamdbas 是可转换为std::function对象的不同类型,但这种转换不是类型推导的一部分。以下是它应该如何工作std::function

template<typename T>
void mapll(std::function<T(T)> f, std::list<T>& l) {
    for(auto it = l.begin(); it != l.end(); ++it) {
        *it = f(*it);
    }
}

/* ... */

mapll(std::function<int(int)>{[](int n) { return n * 2; }}, l);

正如您提到的使用函数指针的可能解决方案,这将是:

template<typename T>
void mapll(int (*f)(int),  std::list<T>& l) {
    /* Function body identical to the one above. */
}

/* ... */

/* The stateless lambda converts to the function pointer: */
mapll([](int n) { return n * 2; }, l);

不幸的是,上面的函数指针在ints 上运行,这在std::list<T>. 使用通用函数指针,mapll函数签名更改为

template<typename T>
void mapll(T (*f)(T),  std::list<T>& l)

但同样,int参数/返回类型的 lamdba 并没有推导出来匹配这个函数指针。你必须明确地转换它:

mapll(static_cast<int(*)(int)>([](int n) { return n * 2; }), l);

请注意,正如评论中指出的那样,您还应该考虑std::transform. mapll而且我已经更改了函数模板的返回值(为 void)和第二个参数类型(为左值引用) 。


推荐阅读