oma*_*mar 2 c++ lambda templates c++11 c++17
在使用C++浏览模板时,我偶然发现了以下代码中的示例:
#include <iostream>
#include <functional>
template <typename T>
void call(std::function<void(T)> f, T v)
{
f(v);
}
int main(int argc, char const *argv[])
{
auto foo = [](int i) {
std::cout << i << std::endl;
};
call(foo, 1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
要编译这个程序,我使用的是GNU C++编译器 g ++:
$ g++ --version // g++ (Ubuntu 6.5.0-1ubuntu1~16.04) 6.5.0 20181026
Run Code Online (Sandbox Code Playgroud)
编译C++ 11后,我收到以下错误:
$ g++ -std=c++11 template_example_1.cpp -Wall
template_example_1.cpp: In function ‘int main(int, const char**)’:
template_example_1.cpp:15:16: error: no matching function for call to ‘call(main(int, const char**)::<lambda(int)>&, int)’
call(foo, 1);
^
template_example_1.cpp:5:6: note: candidate: template<class T> void call(std::function<void(T)>, T)
void call(std::function<void(T)> f, T v)
^~~~
template_example_1.cpp:5:6: note: template argument deduction/substitution failed:
template_example_1.cpp:15:16: note: ‘main(int, const char**)::<lambda(int)>’ is not derived from ‘std::function<void(T)>’
call(foo, 1);
^
Run Code Online (Sandbox Code Playgroud)
(C++ 14和C++ 17相同)
从编译错误和注释我明白编译器无法推断出lambda的类型,因为它无法与std :: function匹配.
看着前面的问题(1,2,3,和4关于此错误的),我仍然感到困惑了.
正如问题3和4的答案所指出的那样,可以通过显式指定模板参数来修复此错误,如下所示:
int main(int argc, char const *argv[])
{
...
call<int>(foo, 1); // <-- specify template argument type
// call<double>(foo, 1) // <-- works! Why?
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然而,当我使用其他类型的,而不是int像double,float,char,或者bool,它可以作为很好,这让我更加困惑.
所以,我的问题如下:
int(和其他人)作为模板参数时,为什么它可以工作?A std::function不是lambda,而lambda不是lambda std::function.
lambda是一个匿名类型,带有operator()一些其他小实用程序.您的:
auto foo = [](int i) {
std::cout << i << std::endl;
};
Run Code Online (Sandbox Code Playgroud)
是简写
struct __anonymous__type__you__cannot__name__ {
void operator()(int i) {
std::cout << i << std::endl;
}
};
__anonymous__type__you__cannot__name__ foo;
Run Code Online (Sandbox Code Playgroud)
非常粗略(有实际的转换功能指针和其他一些我不会涉及的噪音).
但是,请注意,它并没有继承std::function<void(int)>.
lambda不会推导出a的模板参数,std::function因为它们是不相关的类型.模板类型推导是针对传递的参数类型及其基类的精确模式匹配.它不会尝试使用任何类型的转换.
A std::function<R(Args...)>是一种类型,可以存储任何可复制的类型,可以使用与之兼容的值调用Args...并返回与之兼容的内容R.
所以std::function<void(char)>可以存储任何可以用a调用的东西char.因为int函数可以使用a来调用char,这是有效的.
试试吧:
void some_func( int x ) {
std::cout << x << "\n";
}
int main() {
some_func('a');
some_func(3.14);
}
Run Code Online (Sandbox Code Playgroud)
std::function 这是从它的签名到存储在其中的可调用的一些转换.
最简单的解决方案是:
template <class F, class T>
void call(F f, T v) {
f(v);
}
Run Code Online (Sandbox Code Playgroud)
现在,在极少数情况下,您实际上需要签名.您可以在c ++ 17中执行此操作:
template<class T>
void call(std::function<void(T)> f, T v) {
f(v);
}
template<class F, class T>
void call(F f_in, T v) {
std::function f = std::forward<F>(f_in);
call(std::move(f), std::forward<T>(v));
}
Run Code Online (Sandbox Code Playgroud)
最后,你call是std::invoke来自c ++ 17的残缺版本.考虑使用它; 如果没有,请使用backported版本.
| 归档时间: |
|
| 查看次数: |
236 次 |
| 最近记录: |