为什么在C ++ 11中的lambda函数不具有函数<>类型? [英] why do lambda functions in c++11 not have function<> types?

查看:295
本文介绍了为什么在C ++ 11中的lambda函数不具有函数<>类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在玩c ++ 11的功能特性。有一件事我发现奇怪的是,lambda函数的类型实际上不是一个函数<>类型。更重要的是,lambda的类似推理机制似乎不太好。



附加的是一个小例子,其中我测试翻转函数的两个参数添加两个整数。 (在我的例子中, addInt_f 的类型已使用函数<>显式定义,而 addInt_l 是类型为 auto 的类型引用的lambda。



编译代码,翻转函数可以接受明确的类型定义版本的addInt但不是lambda版本,给出一个错误说,
testCppBind.cpp:15:27:error:没有匹配函数调用'flip(< lambda(int,int)&)'



接下来的几行显示,如果将lambda版本(以及raw版本)显式转换为适当的函数<>类型,则可以接受。



所以我的问题是:


  1. 为什么lambda函数没有 function<> 首先输入?在小例子中,为什么 addInt_l function 有不同的 lambda 类型?从函数式编程的角度来看,函数/函数对象和lambda之间有什么区别?


  2. 如果有一个根本原因,不同。我听说lambda可以转换为 function<> 但他们是不同的。这是一个设计问题/缺陷的C ++ 11,一个实现问题或有区别的两个方面的好处吗?似乎 addInt_l 的类型签名已经提供了关于函数的参数和返回类型的足够信息。


  3. <




有没有办法编写lambda,以避免上述显式类型转换?

提前感谢。

  //  -  testCppBind.cpp  -  
#include< functional&
using namespace std;
using namespace std :: placeholders;

template< typename T1,typename T2,typename T3>
function< T3(T2,T1)>翻转(函数< T3(T1,T2)> f){return bind(f,_2,_1);}

function< int addInt_f = [](int a,int b) - > int {return a + b;};
auto addInt_l = [](int a,int b) - > int {return a + b;};

int addInt0(int a,int b){return a + b;}

int main(){
auto ff = flip(addInt_f); // ok
auto ff1 = flip(addInt_l); // not ok
auto ff2 = flip((function< int(int,int)>)addInt_l); // ok
auto ff3 = flip((function< int(int,int)>)addInt0); // ok

return 0;
}

解决方案

std :: function 是一种用于存储任何类型的可调用对象的工具。为了做到这一点,它需要采用一些类型的擦除技术,并涉及一些开销。



任何可调用可以隐式转换为 std :: function ,这就是为什么它通常无缝地工作。



我会重复,以确保它变得清楚: std :: function 不是只用于lambdas或函数指针的东西:它是任何可调用的。这包括例如 struct some_callable {void operator()(){}}; 这是一个简单的,但它可以是这样的东西:

  struct some_polymorphic_callable {
template< typename T>
void operator()(T);
};

lambda只是另一个可调用对象,类似于 some_callable 上面的对象。它可以存储在 std :: function 中,因为它是可调用的,但它没有类型擦除开销 std :: function



委员会计划在未来使lambda类型成为多态,即lambda类似 some_polymorphic_callable 以上。 std :: function 类型会是这样的lambda吗?






Now ...模板参数扣除,或隐式转换。选一个。这是C ++模板的规则。



要将lambda作为 std :: function 参数传递,被隐式转换。取一个 std :: function 参数意味着你选择隐式转换超过类型扣除。但你的函数模板需要显式推导或提供签名。



解决方案?不要限制您的呼叫者 std :: function 。接受任何类型的可呼叫。

 模板< 
自动翻转(有趣&& f) - > decltype(std :: bind(std :: forward< Fun>(f),_ 2,_1))
{return std :: bind(std :: forward& }






我们需要 std :: function std :: function 为具有已知签名的可调用项提供类型擦除。这本质上使存储类型擦除的可调用和写 virtual 接口非常有用。


I am playing around with the c++11 functional features. One thing I find odd is that the type of a lambda function is actually NOT a function<> type. What's more, lambda's do not seem to play really well with the type-inferencing mechanism.

Attached is a small example in which I tested flipping the two arguments of a function for adding two integers. (The compiler I used was gcc 4.6.2 under MinGW.) In the example, the type for addInt_f has been explicitly defined using function<> while addInt_l is a lambda whose type is type-inferenced with auto.

When I compiled the code, the flip function can accept the explicitly type-defined version of addInt but not the lambda version, giving an error saying that, testCppBind.cpp:15:27: error: no matching function for call to 'flip(<lambda(int, int)>&)'

The next few lines show that the lambda version (as well as a 'raw' version) can be accepted if it's explicitly cast to the appropriate function<> type.

So my questions are:

  1. Why is it that a lambda function does not have a function<> type in the first place? In the small example, why does not addInt_l have function<int (int,int)> as the type instead of having a different, lambda type? From the perspective of functional programming, what's the difference between a function/functional object and a lambda?

  2. If there is a fundamental reason that these two have to be different. I heard that lambda's can be converted to function<> but they are different. Is this a design issue/defect of C++11, an implementation issue or is there a benefit in distinguishing the two as the way it is? It seems that the type-signature of addInt_l alone has provided enough information about the parameter and return types of the function.

  3. Is there a way to write the lambda so that the above mentioned explicit type-casting can be avoided?

Thanks in advance.

    //-- 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 { return a + b;};
    auto addInt_l = [](int a,int b) -> int { return a + b;};

    int addInt0(int a, int b) { return a+b;}

    int main() {
      auto ff = flip(addInt_f);   //ok
      auto ff1 = flip(addInt_l);  //not ok
      auto ff2 = flip((function<int (int,int)>)addInt_l); //ok
      auto ff3 = flip((function<int (int,int)>)addInt0);  //ok

      return 0;
    }

解决方案

std::function is a tool useful to store any kind of callable object regardless of its type. In order to do this it needs to employ some type erasure technique, and that involves some overhead.

Any callable can be implicitly converted to a std::function, and that's why it usually works seamlessly.

I'll repeat to make sure it becomes clear: std::function is not something just for lambdas or function pointers: it's for any kind of callable. That includes things like struct some_callable { void operator()() {} };, for example. That is a simple one, but it could be something like this instead:

struct some_polymorphic_callable {
    template <typename T>
    void operator()(T);
};

A lambda is just yet another callable object, similar to instances of the some_callable object above. It can be stored in a std::function because it's callable, but it doesn't have the type erasure overhead of std::function.

And the committee plans to make lambdas polymorphic in the future, i.e., lambdas that look like some_polymorphic_callable above. Which std::function type would such a lambda be?


Now... Template parameter deduction, or implicit conversions. Pick one. That's a rule of C++ templates.

To pass a lambda as a std::function argument, it needs to be implicitly converted. Taking a std::function argument means that you're choosing implicit conversions over type deduction. But your function template needs the signature to be deduced or provided explicitly.

The solution? Don't restrict your callers to std::function. Accept any kind of callable.

template <typename Fun>
auto flip(Fun&& f) -> decltype(std::bind(std::forward<Fun>(f),_2,_1))
{ return std::bind(std::forward<Fun>(f),_2,_1); }


You may now be thinking why do we need std::function then. std::function provides type erasure for callables with a known signature. That essentially makes it useful to store type-erased callables and to write virtual interfaces.

这篇关于为什么在C ++ 11中的lambda函数不具有函数&lt;&gt;类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆