Why use `std::bind_front` over lambdas in C++20?

后端 未结 2 752
臣服心动
臣服心动 2021-02-06 21:10

As mentioned in a similarly worded question (Why use bind over lambdas in c++14?) The answer was - no reason (and also mentioned why it would be better to use lambdas).

M

相关标签:
2条回答
  • 2021-02-06 21:29

    The paper that proposed it Simplified partial function application has some good compelling use cases. I will summarize them here, because otherwise I would have to quote most of the paper, so definitely go check it out:

    Automatic perfect forwarding

    Using a lambda would involve std::forward boilerplate

    Propagating mutability

    In case of storing object by value std::bind and std::bind_front propagate constness, but in the case of capturing lambda the user must chose a mutable or const version creating problems

    Preserving return type

    Using a lambda would involve -> decltype(auto) boilerplate on the user side.

    Preserving value category

    Like preserving mutability, except now we are talking about lvalue/rvalue and only std::bind_front does this correctly

    Supporting one-shot invocation

    A consequence of propagating mutability and preserving value category

    Preserving exception specification

    This is especially more important now since exception specification is now part of type system


    cppreference has some useful notes as well:

    This function is intended to replace std::bind. Unlike std::bind, it does not support arbitrary argument rearrangement and has no special treatment for nested bind-expressions or std::reference_wrappers. On the other hand, it pays attention to the value category of the call wrapper object and propagates exception specification of the underlying call operator.

    0 讨论(0)
  • 2021-02-06 21:39

    bind_front binds the first X parameters, but if the callable calls for more parameters, they get tacked onto the end. This makes bind_front very readable when you're only binding the first few parameters of a function.

    The obvious example would be creating a callable for a member function that is bound to a specific instance:

    type *instance = ...;
    
    //lambda
    auto func = [instance](auto &&... args) -> decltype(auto) {return instance->function(std::forward<decltype(args)>(args)...);}
    
    //bind
    auto func = std::bind_front(&type::function, instance);
    

    The bind_front version is a lot less noisy. It gets right to the point, having exactly 3 named things: bind_front, the member function to be called, and the instance on which it will be called. And that's all that our situation calls for: a marker to denote that we're creating a binding of the first parameters of a function, the function to be bound, and the parameter we want to bind. There is no extraneous syntax or other details.

    By contrast, the lambda has a lot of stuff we just don't care about at this location. The auto... args bit, the std::forward stuff, etc. It's a bit harder to figure out what it's doing, and it's definitely much longer to read.

    Note that bind_front doesn't allow bind's placeholders at all, so it's not really a replacement. It's more a shorthand for the most useful forms of bind.

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