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_ifwould return an iterator to an element which is in amoved-fromstate. And all other elements would be moved whose are checked with the predicate. Thats why I suppose find_if does notmoves the elements for checking predicates.
For other algorithms, like std::accumulate ignoring the rvalue-reference case can cause performance issues.
