Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is templated functor passed as value and not forwarding reference

In discussion we had here I was playing around with passing functors. C++ STL passes functors as values (seen in std::for_each, std::find_if, std::transform)

So declaring mine would be like this.

template<typename F>
void call_me(F f)
{
    f();
}

Now, calling call_me(ftor{}) could probably invoke ftor's copy constructor (it will most likely be copy elided, so not the case). But ftor f{}; call_me(f); will result in copying. If ftor has large data, it might be an issue.

We'll improve it by passing it as const reference (void call_me(const F& f)) to get rid of unneeded copy. This is fine as long as ftor::operator() is const. If it is not, the call to call_me would result in compilation error (losing const qualifiers).

So, why to bother with const reference, use just reference (void call_me(F& f)). This is fine, but it would not work for first case being call_me(ftor{}) since binsing r-value to (non-const) l-value reference is not valid.

Declaring f as forwarding reference (void call_me(F&& f)) seems to work in all cases. I believe, that this works thanks to reference collapsing.

So, why are templated functors not passed as forwarding references in functions from STL?

like image 778
Zereges Avatar asked Jul 13 '16 16:07

Zereges


People also ask

How does a functor work?

A functor (or function object) is a C++ class that acts like a function. Functors are called using the same old function call syntax. To create a functor, we create a object that overloads the operator(). The line, MyFunctor(10); Is same as MyFunctor.

What is functor for?

A C++ functor (function object) is a class or struct object that can be called like a function. It overloads the function-call operator () and allows us to use an object like a function.

Are functors part of STL?

Function objects (also called functors) are an STL feature that you may not employ immediately when you start using the STL. They are, however, very useful in many situations and an STL facility with which you should become acquainted.


1 Answers

why are templated functors not passed as r-value references in functions from STL?

First of all, they'd be forwarding references, not rvalue references.

That said, as with many "why" questions about language design in general, the answer can simply be: because nobody has proposed this change yet (see how to submit a proposal). I suspect a great deal of function objects passed into the standard library algorithms are either lambdas, stateless, or extremely cheaply copyable. Moreover, if you have such an expensive object you can always turn in it into a cheaply copyable one for the purposes of the algorithm:

call_me(std::ref(huge_object));

Lastly, some of these algorithms rely upon passing these functions objects around to other helpers. If the algorithm simply assumes that the function object is "free" to copy, this makes it easy to code. If we introduce the possibility of rvalues here, this adds another layer of questions that need to be dealt with - do we just pass in the reference around? What about function objects with ref-qualified operator()?

Some combination of the above probably explains why, e.g., it's still:

template <class InputIt, class UnaryPredicate>
InputIt find_if(InputIt, InputIt, UnaryPredicate );

and not

template <class InputIt, class UnaryPredicate>
InputIt find_if(InputIt, InputIt, UnaryPredicate&& );
like image 123
Barry Avatar answered Oct 19 '22 19:10

Barry