通过参数传递 lambda(无函数类型模板)
Pass lambda by argument (no function type template)
我想在此处不使用函数模板传递 lambda,而是使用 std::function
或类型化函数指针。
#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++11 does not deduce type when std::function or lambda functions are involved
如果你想要一个通用的解决方案,你需要通过函数指针类型定义lambda类型:
typedef int(*funPtrType)(int); // define function pointer type
template<typename T>
void mapll(const funPtrType f, std::list<T>& l) {
// code here
}
然后这样称呼它:
mapll([](int n) { return n * 2; }, l);
以上方案只能用于int
类型。如果你想使用通用数据类型,你需要使用这个:
template<typename T>
void mapll(T (*f)(T), std::list<T>& l) {
// code here
}
那么您可以:
将 lambda 显式转换为函数指针类型:
mapll(static_cast<int(*)(int)>([](int n) { return n * 2; }), l);
^^^^^^^^^^^^^^^^^^^^^^^^
或
明确指定或限定模板参数的类型T
喜欢:
mapll<int>([](Type n) { return n * 2; }, l);
^^^^^
然而,最简单的解决方案是为函数指针添加一个模板参数,让编译器决定类型。
template<typename T, typename FunPtr> // template para for function pointer
void mapll(FunPtr f, std::list<T>& l) {
// code here
}
注意:您不是从函数返回列表。因此,将其设为 void 函数并通过 ref 传递列表,如图所示。
不推导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);
不幸的是,上面的函数指针在 int
s 上运行,这在 std::list<T>
的函数模板中没有意义。使用通用函数指针,mapll
函数签名更改为
template<typename T>
void mapll(T (*f)(T), std::list<T>& l)
但同样,int
argument/return 类型的 lamdba 未被推导为匹配此函数指针。你必须明确地投射它:
mapll(static_cast<int(*)(int)>([](int n) { return n * 2; }), l);
请注意,正如评论中指出的,您还应该考虑 std::transform
。我已经更改了 return 函数模板的 return 值(为 void)和第二个参数类型(为左值引用)。
我想在此处不使用函数模板传递 lambda,而是使用 std::function
或类型化函数指针。
#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++11 does not deduce type when std::function or lambda functions are involved
如果你想要一个通用的解决方案,你需要通过函数指针类型定义lambda类型:
typedef int(*funPtrType)(int); // define function pointer type
template<typename T>
void mapll(const funPtrType f, std::list<T>& l) {
// code here
}
然后这样称呼它:
mapll([](int n) { return n * 2; }, l);
以上方案只能用于int
类型。如果你想使用通用数据类型,你需要使用这个:
template<typename T>
void mapll(T (*f)(T), std::list<T>& l) {
// code here
}
那么您可以:
将 lambda 显式转换为函数指针类型:
mapll(static_cast<int(*)(int)>([](int n) { return n * 2; }), l); ^^^^^^^^^^^^^^^^^^^^^^^^
或
明确指定或限定模板参数的类型
T
喜欢:mapll<int>([](Type n) { return n * 2; }, l); ^^^^^
然而,最简单的解决方案是为函数指针添加一个模板参数,让编译器决定类型。
template<typename T, typename FunPtr> // template para for function pointer
void mapll(FunPtr f, std::list<T>& l) {
// code here
}
注意:您不是从函数返回列表。因此,将其设为 void 函数并通过 ref 传递列表,如图所示。
不推导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);
不幸的是,上面的函数指针在 int
s 上运行,这在 std::list<T>
的函数模板中没有意义。使用通用函数指针,mapll
函数签名更改为
template<typename T>
void mapll(T (*f)(T), std::list<T>& l)
但同样,int
argument/return 类型的 lamdba 未被推导为匹配此函数指针。你必须明确地投射它:
mapll(static_cast<int(*)(int)>([](int n) { return n * 2; }), l);
请注意,正如评论中指出的,您还应该考虑 std::transform
。我已经更改了 return 函数模板的 return 值(为 void)和第二个参数类型(为左值引用)。