问题描述
这看起来类似于"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);
第二个参数是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>
直接转换为参数类型{{ 1}} –考虑到std::function<T(int)>
是v
类型,应该知道std::vector<int>
是T
吗?我想使用lambda表达式的全部原因就是,它是一个 expression ,因此我应该能够在函数调用参数列表中内联编写它,而不必给它起名称或赋值变成变量。
解决方法
问题是,template argument deduction不考虑隐式转换(从lambda到std::function
),这导致第二个函数参数T
上的keyFunc
推导为失败。
类型推导不考虑隐式转换(上面列出的类型调整除外):这是overload resolution的工作,以后会发生。
您可以使用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:
(重点是我的)
在以下情况下,类型,模板和非类型值 用于撰写
P
不参与模板参数 推导,而是使用 推导到其他地方或明确指定。如果模板参数是 仅在非推论上下文中使用且未明确指定, 模板参数推导失败。
- 嵌套名称说明符(范围左侧的所有内容 解析运算符
::
)的类型使用 qualified-id: