Why doesn't std :: find_if (first, last, p) take a predicate by reference?

I looked at various signatures for std::find_if on cppreference.com, and I noticed that there are flavors that use the predicate function to take it by value:

 template< class InputIt, class UnaryPredicate > InputIt find_if( InputIt first, InputIt last, UnaryPredicate p ); 

If I understand them correctly, lambdas with captured variables set aside storage for links or copies of their data, and therefore presumably "bandwidth" means that copies of the captured data will be copied for invocation.

On the other hand, for function pointers and other directly addressed things, performance should be better if a function pointer is passed directly, rather than a pointer to a pointer (pointer to a pointer).

Firstly, is this correct? Is the above UnaryPredicate byte parameter?

Secondly, my understanding of the correct passage of the lambda?

Thirdly, is there any reason to go by value instead of reference in this situation? And what's more, is there some kind of ambiguous syntax (hi, universal link) that would allow the compiler to do whatever it needs to get maximum performance?

+5
source share
2 answers

Is the above UnaryPredicate byte parameter?

Yes, this is what it says in the function parameter list. It takes the type of value displayed.

Also, lambda expressions are prvalues. Meaning, with guaranteed copy elision that p initialized directly from the lambda expression. No additional copies of the closure or captured objects are made when passing it to a function (a function can make more copies inside, although this is not often).

If the predicate was passed by reference, the temporary object must be materialized. Thus, nothing is obtained for a lambda expression using the switch for passing by reference.

If you have other kinds of predicates that are expansive for copying, then you can pass std::reference_wrapper to this predicate object for a cheap descriptor. The wrapper operator() will do the right thing.

The definition is mostly historical, but currently it really is not a problem to do this with a transition by value.


To clarify why reference semantics would suck, try taking it over the years. A simple lvalue reference will not be executed, since now we do not support binding to rvalue. The link to the llue constant will also not be executed, since now we require that the predicate does not change any internal state, and why?

So, before , we have no alternative. Passing by value will be better than a link. With the new standard, we can redefine our approach. To support rvalues, we can add rvalue reference overloading. But this exercise is in redundancy, because he does not need to do anything.

Passing the value, the caller has a choice in how to create it, and for prvalues, in , it's practically free. If the calling user so desires, they can provide referential semantics explicitly. Therefore, nothing is lost, and I think a lot is achieved in terms of ease of use and design of the API.

+8
source

There are several reasons:

  • you can always turn the arguments of the output value into using reference semantics, but not vice versa: just pass std::ref(x) instead of x . `std :: reference_wrapper is not exactly equivalent to passing a link, but especially for the function object that it does on the right. That is, passing general arguments by value is a more general approach.
  • Passing by reference ( T& ) does not work for temporary or const objects, T const& does not work for non const& , i.e. the only choice would be T&& (link forwarding), which pre-C ++ 11 did not exist, and the algorithm interfaces have not changed since they were introduced with C ++ 98.
  • Value parameters can be copied unlike any reference parameters, including forwarding links.

As a result

+3
source

Source: https://habr.com/ru/post/1275375/


All Articles