如何绕过 C++ 无法使用 lambda 匹配模板中的函数类型
How to bypass C++ inability to match function types in templates with lambdas
如果您有以下过滤列表模板:
template <typename T>
inline std::list<T> list_filter(std::list<T> const& a, bool (f)(T)) {
std::list<T> output;
std::copy_if(a.begin(), a.end(), std::back_inserter(output), f);
return output;
}
然后尝试用里面的 lambda 调用它,例如:
std::list<int> lst = {1,2,3,4,5};
auto filtered = list_filter(lst, [](int el) -> bool { return (el % 2 == 0); });
它会产生 no matching function for call to list_filter(..., std::__cxx11::list<int>)::<lambda(int)>)'
的错误。
有没有什么方法可以绕过该限制而不将 lambda 提取到单独的函数中?为什么 C++ 不允许这种明显的模式?
隐式转换(从没有 capture-list 的 lambda 到函数指针)不会在 template argument deduction 中被考虑,这无法在第二个函数参数上推导出模板参数 T
。
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
您可以通过 static_cast
或 operator+
将 lambda 显式转换为函数指针。例如
auto filtered = list_filter(lst, +[](int el) -> bool { return (el % 2 == 0); });
或使用 std::type_identity
(C++20 起)从推导中排除第二个函数参数。例如
template <typename T>
inline std::list<T> list_filter(std::list<T> const& a, bool (f)(std::type_identity_t<T>)) {
...
}
顺便说一句,如果您的编译器不支持 C++20,您可以轻松地制作自己的 type_identity
。
带有捕获的 Lambda 与指向函数的指针不兼容(参数 f
是什么)。
我建议您在涉及可调用对象时从标准库本身获取提示:对整个可调用对象使用模板参数:
template <typename T, typename F>
inline std::list<T> list_filter(std::list<T> const& a, F f) {
std::list<T> output;
std::copy_if(a.begin(), a.end(), std::back_inserter(output), f);
return output;
}
如果您有以下过滤列表模板:
template <typename T>
inline std::list<T> list_filter(std::list<T> const& a, bool (f)(T)) {
std::list<T> output;
std::copy_if(a.begin(), a.end(), std::back_inserter(output), f);
return output;
}
然后尝试用里面的 lambda 调用它,例如:
std::list<int> lst = {1,2,3,4,5};
auto filtered = list_filter(lst, [](int el) -> bool { return (el % 2 == 0); });
它会产生 no matching function for call to list_filter(..., std::__cxx11::list<int>)::<lambda(int)>)'
的错误。
有没有什么方法可以绕过该限制而不将 lambda 提取到单独的函数中?为什么 C++ 不允许这种明显的模式?
隐式转换(从没有 capture-list 的 lambda 到函数指针)不会在 template argument deduction 中被考虑,这无法在第二个函数参数上推导出模板参数 T
。
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
您可以通过 static_cast
或 operator+
将 lambda 显式转换为函数指针。例如
auto filtered = list_filter(lst, +[](int el) -> bool { return (el % 2 == 0); });
或使用 std::type_identity
(C++20 起)从推导中排除第二个函数参数。例如
template <typename T>
inline std::list<T> list_filter(std::list<T> const& a, bool (f)(std::type_identity_t<T>)) {
...
}
顺便说一句,如果您的编译器不支持 C++20,您可以轻松地制作自己的 type_identity
。
带有捕获的 Lambda 与指向函数的指针不兼容(参数 f
是什么)。
我建议您在涉及可调用对象时从标准库本身获取提示:对整个可调用对象使用模板参数:
template <typename T, typename F>
inline std::list<T> list_filter(std::list<T> const& a, F f) {
std::list<T> output;
std::copy_if(a.begin(), a.end(), std::back_inserter(output), f);
return output;
}