Home > Enterprise >  Using perfect fowarding in STL predicate
Using perfect fowarding in STL predicate

Time:01-05

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.

CodePudding user response:

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).

CodePudding user response:

In general it could make sense to perfect forwarding an argument, but it depends on its internals: does myFunction takes advantage of forwarding or not?

In this particular case - as a predicate - it is not recommended: I suppose that find_if never moves elements when it calls the predicate.

But if it would then:

  • if myFunction takes it argument by lvalue reference, then nothing happens, so perfect forwarding is just a syntactic noise compared to the simple const auto& case.
  • on the other hand: if myFunction can take its argument by rvalue reference (consumes it), then find_if would return an iterator to an element which is in a moved-from state. And all other elements would be moved whose are checked with the predicate. Thats why I suppose find_if does not moves the elements for checking predicates.

For other algorithms, like std::accumulate ignoring the rvalue-reference case can cause performance issues.

  •  Tags:  
  • Related