这个问题在这里已经有了答案:
C++11 does not deduce type when std::function or lambda functions are involved
(3 个回答)
去年关闭。
我正在尝试围绕 C++ lambda 表达式和模板的交互进行思考。
此代码按我的预期工作:
#include <iostream>
int bar (int x, int (* f) (int))
{
return f (x);
}
double bar (double x, double (* f) (double))
{
return f (x);
}
int main ()
{
std::cout << bar (16, [] (int x) -> int { return x * x; }) << std::endl;
std::cout << bar (1.2, [] (double x) -> double { return x * x; }) << std::endl;
return 0;
}
这样做也是如此:
#include <iostream>
#include <functional>
int bar (int x, std::function<int (int)> f)
{
return f (x);
}
double bar (double x, std::function<double (double)> f)
{
return f (x);
}
int main ()
{
std::cout << bar (16, [] (int x) -> int { return x * x; }) << std::endl;
std::cout << bar (1.2, [] (double x) -> double { return x * x; }) << std::endl;
return 0;
}
到现在为止还挺好。但以下示例均无法编译:
#include <iostream>
template <typename T>
T bar (T x, T (* f) (T))
{
return f (x);
}
int main ()
{
std::cout << bar (16, [] (int x) -> int { return x * x; }) << std::endl;
std::cout << bar (1.2, [] (double x) -> double { return x * x; }) << std::endl;
return 0;
}
和
#include <iostream>
#include <functional>
template <typename T>
T bar (T x, std::function <T (T)> f)
{
return f (x);
}
int main ()
{
std::cout << bar (16, [] (int x) -> int { return x * x; }) << std::endl;
std::cout << bar (1.2, [] (double x) -> double { return x * x; }) << std::endl;
return 0;
}
GCC 版本 8.3.0(使用 -std=c++17)给出了一条错误消息:
no matching function for call to 'bar(int, main()::<lambda(int)>' (and
another for the "double" version) and "template argument
deduction/substitution failed: main()::<lambda(int)> is not derived
from std::function<T(T)>" (for the second failing example).
但是,此任务有效:
std::function<int (int)> f = [] (int x) -> int { return x * x; };
任何人都可以为我照亮吗? (显然,这不是实用的代码。这只是学习的尝试。)
最佳答案
问题是在 template argument deduction 中不会考虑隐式转换(从 lambda 到函数指针或 std::function
) ;然后在您的第三个和第四个样本类型扣除 T
第二个函数参数(即 lambda)失败。
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
在这种情况下
T
只能从第一个函数参数中推导出来;你可以用 non-deduced context 声明第二个, 将其排除在扣除范围之外。例如
template <typename T>
T bar (T x, std::type_identity_t<T (*) (T)> f)
{
return f (x);
}
template <typename T>
T bar (T x, std::type_identity_t<std::function <T (T)>> f)
{
return f (x);
}
PS:
std::type_identity
可以从 C++20 获得,在此之前您可以自己制作一个,这并不困难。LIVE
关于c++ - C++ lambdas 和模板的交互,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61626853/