将 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)>
——而且考虑到v
是std::vector<int>
类型,应该知道T
是int
吧?我想使用 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.
- The nested-name-specifier (everything to the left of the scope
resolution operator
::
) of a type that was specified using a
qualified-id:
这可能看起来类似于 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)>
——而且考虑到v
是std::vector<int>
类型,应该知道T
是int
吧?我想使用 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.
- The nested-name-specifier (everything to the left of the scope resolution operator
::
) of a type that was specified using a qualified-id: