Search code examples
c++lambdastlpredicateperfect-forwarding

Using perfect fowarding in STL predicate


Does it make sense to use perfect forwarding in some STL algorithm ? What will be the deduced type ?

auto it = std::find_if(cont.cgebin(),
                       cont.cend(),
                       [](auto&& element){ return myFunction(std::forward<decltype(element)>(element)); })

I suppose the L-value version will be used (what about const ?), but what does determine that ? Is there other algorithms which would send a R-value ? I don't think so, because it would mean the predicate could be "consume" the element, whatever the result of the predicate.


Solution

  • The deduced type of element depends on how the lambda is used within find_if.

    find_if will never move by itself (you could pass a movable-iterator to find_if, but then it's not find_if that's doing the move, but the dereference operator on the iterator). find_if will pass the value returned by the dereference operator to the lambda, so in your case it's most likely1 const T& (it could well be T& if you had a non-const container and used begin/end).

    In both const T& and T& cases, std::forward will do nothing, so you will just pass the parameter to myFunction.

    Note that the standard requires the predicate of std::find_if to not modify its argument, so if you have myFunction(T&) that modifies its argument, your code has undefined behavior.

    You should not std::forward here since there is no reason to accept an argument in find_if using anything else than const T&, so a better version would be2:

    auto it = std::find_if(cont.cbegin(), cont.cend(),
                           [](const auto& element){ return myFunction(element); });
    

    1 Some weird containers (std::vector<bool>) will not return a const bool& but a proxy-object, so your lambda needs to take a const auto& or auto&&, auto& will be a compile-time error.

    2 Some people (a lot?) uses auto&& in these case, without the std::forward of course, because it's shorter and gives you consistent lambda (you use auto&& everywhere for the lambda).