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

Ana*_*and 1 c++ lambda templates std-function template-argument-deduction

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

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

第二个参数是std::function映射Tint(按值传递)的 。

在调用这个时,我想使用一个 lambda 表达式,如下:

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

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

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

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

son*_*yao 6

问题是,模板参数推导不考虑隐式转换(从 lambda 到std::function),这会导致T第二个函数参数的推导keyFunc失败。

类型推导不考虑隐式转换(上面列出的类型调整除外):这是重载解析的工作,稍后会发生。

您可以使用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);
Run Code Online (Sandbox Code Playgroud)

BTW:如果你的编译器不支持 std::type_identity,那么制作一个并不难。

关于std::type_identity这里的工作原理,请参阅非推断上下文

(强调我的)

在以下情况下,用于组合的类型、模板和非类型值P 不参与模板参数推导,而是使用在其他地方推导或明确指定的模板参数。如果模板参数仅在非推导上下文中使用且未明确指定,则模板参数推导失败。

  1. 使用限定 id指定的类型的嵌套名称说明符(范围解析运算符左侧的所有内容::) :