将 lambda 参数传递给没有中间变量的 std::function 参数

Passing a lambda argument to a std::function parameter without intermediate variable

这可能看起来类似于 ,但我实际上是按值传递 std::function 参数,因此该问题不适用。我定义了以下函数。

template<typename T>
std::vector<T> countSort(const std::vector<T> &v, std::function<int(T)> keyFunc, int n);

第二个参数是一个 std::function,它将 T 映射到 int(按值传递)。

调用这个的时候,我想用lambda表达式,如下:

std::vector<int> v;
[...]
v = countSort(v, [](int x) { return x; }, 10);

但是模板参数推导失败,因为“main()::<lambda(int)> 不是从 std::function<int(T)> 派生的”。如果我指定模板参数,或者如果我为 lambda 表达式引入类型为 std::function 的中间变量,它确实有效:

std::function<int(int)> lambda = [](int x) { return x; };
v = countSort(v, lambda, 10);

为什么我不能做前者?我给了编译器完全相同的信息;如果在给变量赋值时能够将类型lambda<int>的值转换为std::function<int(int)>,为什么不能直接从lambda<int>转换为参数类型,即std::function<T(int)>——而且考虑到vstd::vector<int>类型,应该知道Tint吧?我想使用 lambda 表达式的全部原因恰恰是,它是一个 表达式 ,所以我应该能够在函数调用参数列表中内联写入它,而不必给它一个命名或将其分配给变量。

问题是,template argument deduction 没有考虑隐式转换(从 lambda 到 std::function),这导致在第二个函数参数 keyFunc 上扣除 T ] 失败。

Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.

您可以使用 std::type_identity (C++20 起)从推导中排除第二个函数参数。例如

template<typename T>
std::vector<T> countSort(const std::vector<T> &v, std::function<int(std::type_identity_t<T>)> keyFunc, int n);

顺便说一句:如果你的编译器不支持std::type_identity,那么制作一个也不难。

关于 std::type_identity 如何在这里工作,请参阅 non-deduced context:

(强调我的)

In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

  1. The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id: