如何绕过 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_castoperator+ 将 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;
}