Ken*_*lou 5 c++ lambda templates c++17
我正在尝试围绕 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;
}
Run Code Online (Sandbox Code Playgroud)
这样做也是如此:
#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;
}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好。但以下示例均无法编译:
#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;
}
Run Code Online (Sandbox Code Playgroud)
和
#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;
}
Run Code Online (Sandbox Code Playgroud)
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).
Run Code Online (Sandbox Code Playgroud)
但是,此任务有效:
std::function<int (int)> f = [] (int x) -> int { return x * x; };
Run Code Online (Sandbox Code Playgroud)
任何人都可以为我照亮吗?(显然,这不是实用的代码。这只是学习的尝试。)
问题是std::function
在模板参数推导中不会考虑隐式转换(从 lambda 到函数指针或);然后在你的第三个和第四个样本类型推导中T
,第二个函数参数(即 lambda)失败。
类型推导不考虑隐式转换(上面列出的类型调整除外):这是重载解析的工作,稍后会发生。
在这种情况下T
,只能从第一个函数参数中推导出来;您可以使用非推导上下文声明第二个,以将其从推导中排除。
例如
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);
}
Run Code Online (Sandbox Code Playgroud)
PS:std::type_identity
从C++20开始就可以了,在此之前你可以自己做一个,不难。
您的失败代码在模板参数推导过程中需要函数指针,而 lambda 不是函数指针。
但是,像您这样的非捕获 lambda 可以转换为函数指针。
最简洁的方法是应用一元+
。这+
是有效的,因为 a对指针有效,在模板替换发生之前触发转换。
#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;
// ^ this is the only change
std::cout << bar (1.2, +[] (double x) -> double { return x * x; }) << std::endl;
// ^ this is the only change
return 0;
}
Run Code Online (Sandbox Code Playgroud)
可能不是您真正需要的,但它可以使用C++11
(因为Lambda 函数只是匿名函子的语法糖):
#include <iostream>
template <typename T, typename L>
T bar (T x, const L& l)
{
return l (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;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
87 次 |
最近记录: |