我正在玩c ++ 11的功能.我发现奇怪的一件事是lambda函数的类型实际上不是函数<>类型.更重要的是,lambda似乎不能很好地使用类型推理机制.
附件是一个小例子,我在其中测试了翻转函数的两个参数以添加两个整数.(我使用的编译器是MinGW下的gcc 4.6.2.)在示例中,类型for addInt_f已使用函数<>显式定义,而addInt_l类型为类型推理的lambda auto.
当我编译的代码,该flip功能可以接受明确类型定义addInt的版本,但不是拉姆达版本,给了一个错误说,
testCppBind.cpp:15:27: error: no matching function for call to 'flip(<lambda(int, int)>&)'
接下来的几行显示lambda版本(以及'raw'版本)如果显式转换为适当的函数<>类型,则可以接受.
所以我的问题是:
为什么lambda函数首先没有function<>类型?在小例子中,为什么不addInt_l具有function<int (int,int)>类型而不是具有不同的lambda类型?从函数式编程的角度来看,函数/函数对象和lambda之间有什么区别?
如果存在这两者必须不同的根本原因.我听说lambda可以转换为function<>但它们是不同的.这是C++ 11,一个执行问题是设计问题/缺陷还是有区分两者,因为它是方式的好处?似乎addInt_l单独的类型签名提供了关于函数的参数和返回类型的足够信息.
有没有办法编写lambda,以便可以避免上面提到的显式类型转换?
提前致谢.
//-- testCppBind.cpp --
#include <functional>
using namespace std;
using namespace std::placeholders;
template <typename T1,typename T2, typename T3>
function<T3 (T2, T1)> flip(function<T3 (T1, T2)> f) { return bind(f,_2,_1);}
function<int (int,int)> addInt_f = [](int a,int b) -> int …Run Code Online (Sandbox Code Playgroud) 我想知道是否有一种标准方法来获取任何给定lambda的参数的类型签名(即返回类型和类型)?
我问的原因是我一直想知道auto声明中的类型究竟是什么样的auto l =[](int x,int y)->int{return x+y;}.在其他用例中auto,对于较长的类型名称而言,它是一种便利和更短的替代方案.但是对于lambdas,是否有另一种方法来声明lambda变量?
我的理解是标准lambda只不过是一个函数对象,它是它自己的类型.因此,即使两个lambda具有相同的返回类型和参数类型,它们仍然是两个不同的,不相关的类/仿函数.但是有一种方法可以捕捉它们在类型签名方面相同的事实吗?
我认为我正在寻找的类型签名可能类似于std::function<>正确类型的对象.
更有用/涉及的问题是,如果可以提取类型签名,则可以编写一般包装函数将任何lambda函数转换std::function为相同类型签名的对象.
首先,我正在使用C++ 11(我的主题很糟糕).
我要做的是编写一个通用模板函数,它实现了通常sort_by在其他编程语言中调用的东西.它涉及精确计算一个范围的每个成员的任意标准,然后根据这些标准对该范围进行排序.这样的标准不一定是POD,它必须是低于可比性的.对于std::less不起作用的东西,调用者应该能够提供她自己的比较函子.
我已经成功编写了使用以下签名的函数:
template< typename Tcriterion
, typename Titer
, typename Tcompare = std::less<Tcriterion>
>
void
sort_by(Titer first, Titer last,
std::function<Tcriterion(typename std::iterator_traits<Titer>::value_type const &)> criterion_maker,
Tcompare comparator = Tcompare()) {
}
Run Code Online (Sandbox Code Playgroud)
它可以像这样使用:
struct S { int a; std::string b; double c; };
std::vector<S> s_vec{
{ 42, "hello", 0.5 },
{ 42, "moo!", 1.2 },
{ 23, "fubar", 0.2 },
};
sort_by1< std::pair<int, double> >(
s_vec.begin(), s_vec.end(),
[](S const &one_s) { return std::make_pair(one_s.a, one_s.c); }
); …Run Code Online (Sandbox Code Playgroud) 我正在尝试编写一个包装器make_function,它std::make_pair可以std::function用合适的可调用对象创建一个对象.
就像make_pair对于函数指针一样foo,auto f0 = make_function(foo);创建一个正确类型签名的std::function函数对象f0.只是为了澄清,我不介意偶尔给出类型参数make_function,以防很难(或不可能)从参数中完全推断出类型.
到目前为止我提出的(下面的代码)适用于lambdas,一些函数指针和函子(我没有考虑挥发性).但我无法让它起作用std::bind或std::bind<R>结果.在下面的代码中
auto f2 = make_function(std::bind(foo,_1,_2,_3)); //not OK
Run Code Online (Sandbox Code Playgroud)
不会编译/工作,使用gcc 4.8.1.我猜测,我没有捕捉到operator()了bind正确的结果,但我不知道如何解决它.
任何有关如何解决此案例或改善其他角落案件的帮助表示赞赏.
当然,我的问题是如何修复下面示例中的错误.
对于后台,我可以在这个问题中找到我使用此包装器的一种情况:如何使C++ 11函数采用函数<>参数自动接受lambdas.如果您不批准使用std::function或以我的具体使用方式,请在该帖子中留下您的意见,并在此处讨论技术问题.
---编辑---
从一些评论中,我了解到这是因为模糊性问题(std::bind结果函数调用operator()的模糊性).正如@Mooing Duck的回答所指出的,解决方案是明确地给出参数类型.我已经更新了代码以结合@Mooing Duck的答案中的三个函数(稍微更改了类型参数),这样make_function包装器现在可以像以前一样处理/类型推导明确的情况,并允许指定完整类型签名歧义.
(我的明确案例的原始代码位于:https://stackoverflow.com/a/21665705/683218,可在以下网址进行测试:https://ideone.com/UhAk91):
#include <functional>
#include <utility>
#include <iostream>
#include <functional>
using namespace std;
// For …Run Code Online (Sandbox Code Playgroud) 我来自Haskell,目前正在修补C++ 11以了解它能做些什么.我的一个玩具是一个小模板,试图模仿Haskell map函数,即它需要一个容器的值X和一个函数映射X到a Y并产生一个容器的值Y.我知道我可以轻松地使用std::transform,但这会破坏乐趣.
现在,我的模板看起来像这样:
template <typename T, typename U>
void myMap( const T &input,
U &output,
std::function<typename U::value_type (typename T::value_type)> f );
Run Code Online (Sandbox Code Playgroud)
现在,我的qustion是:是否有可能调整的签名,以便而不是按引用以输出容器(第二个参数)通过我的返回值产生一个新的容器,但编译器可以推断的返回类型?就像是
template <typename T, typename U>
U myMap( const T &input,
std::function<typename U::value_type (typename T::value_type)> f );
Run Code Online (Sandbox Code Playgroud)
不幸的是不能称之为
std::vector<int> x = { 1, 2, 3, 4 };
std::list<bool> y = myMap( x, []( int x ) { return x % 2 == 0; } );
Run Code Online (Sandbox Code Playgroud)
......至少Clang在这里没有推断出返回类型.
我有一个想法是,由于输入容器类型和函数类型是已知的,您可以从中构造输出类型.就是这样的 …
我试图理解我在下面的代码中遇到的编译器错误。我有一个可变参数模板函数,它接受具有指定类型的 lambda,并尝试调用该函数会导致模板由于不匹配而未被视为有效候选者。
#include <functional>
template<typename ... ResultTypes>
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
{
}
int main(int argc, char **argv)
{
executeWithResultHandler<int>([] (int arg) {
});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这会导致以下错误:
$ c++ -std=c++11 reduction.cpp
reduction.cpp:10:5: error: no matching function for call to 'executeWithResultHandler'
executeWithResultHandler<int>([] (int arg) {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
reduction.cpp:4:6: note: candidate template ignored: could not match 'function<void (int, type-parameter-0-0...)>' against
'<lambda at reduction.cpp:10:35>'
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
如果我将声明更改为非可变参数:
template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{
}
Run Code Online (Sandbox Code Playgroud)
那么它适用于上面的玩具示例,但对于真正的问题,我需要任意参数。我在这里遗漏了什么,或者用另一种方式来完成这个?
编辑:这被错误地标记为重复,我相信 …