why do lambda functions in c++11 not have function<> types?

后端 未结 2 1047
太阳男子
太阳男子 2020-11-29 07:22

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

相关标签:
2条回答
  • 2020-11-29 08:03
    1. Because function<> employs type erasure. This allows several different function-like types to be stored in a function<>, but incurs a small runtime penalty. Type erasure hides the actual type (your specific lambda) behind a virtual function interface.
    2. There is a benefit to this: one of the C++ design "axioms" is to never add overhead unless it is really needed. Using this setup, you do not have any overhead when using type inference (use auto or pass as a template parameter), but you still have all the flexibility to interface with non-template code through function<>. Also note that function<> is not a language construct, but a component of the standard library that can be implemented using simple language features.
    3. No, but you can write the function to just take the type of the function (language construct) instead of the specifics of the function<> (library construct). Of course, that makes it a lot harder to actually write down the return type, since it does not directly give you the parameter types. However, using some meta-programming a la Boost.FunctionTypes you can deduce these from the function you pass in. There are some cases where this is not possible though, for example with functors that have a templated operator().
    0 讨论(0)
  • 2020-11-29 08:08

    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.

    0 讨论(0)
提交回复
热议问题