What is the correct argument type for the object object?

I have a boilerplate function that receives function objects. Sometimes function objects are assembler structures, but sometimes they are large statefull objects. The state of the function-object does not change in this function, but is only checked. I also really want to write code that the compiler can optimize as much as possible. What to consider when choosing an argument type?

A function of this type:

template<typename funcT> auto make_particle(funcT fun) { Particle<typename funcT::result_type> particle; particle = fun(); return particle; } 

The argument type must be funcT const & fun , so large objects are not copied, but why do most people use function objects by default? Am I losing something using the const link? Or should I use lvalue-reference? Please note that C ++ 1y is okay and that the code example above is just an example.

+8
c ++ function-object
source share
2 answers

The type of the argument should probably be funcT const and fun, so that large objects are not copied,

This is not the look considered by algorithms in standard libraries. There called objects are taken by value. It depends on the author of the called object so that it is cheap enough to copy. For example, if he needs access to something big, then you can force the functor user to provide a link to him and save it in the functor - copying the link is cheap.

Now it’s possible that you want to do something different than the standard library, because you expect an unusually complex job of creating particles to make it cheap to copy or move. But C ++ programmers are familiar with copying functors, so if you do what the standard library does, you usually don't make your life worse than they were. Copying functors is not a problem unless you do this :-)

+5
source share

There are several use cases that should be available:

  • The functor has no state and is provided as temporary: make_particle(MyFun())

  • The functor has a state that needs to be restored later: YourFun f; make_particle(f); YourFun f; make_particle(f);

You cannot solve both cases with one parameter of a reference type: the first case requires a reference to the constant lvalue or the reference value rvalue, which prohibits second use, and the second case requires a reference lvalue, which prohibits first use.

A common idiom in such situations is to take a functor by value and return it at the end:

 template <typename Iter, typename F> F map(Iter first, Iter last, F f) { // ... f(*first) ... return f; } 

This may not be entirely applicable in your case, but it is an idea. For example, you can return std::pair<ParticleType, F> . In any case, you need your functor type to be copied, but this is a reasonable requirement.

An alternative useful to @Xeo and available only to function templates is to accept a functor argument as a universal reference, which will work in both cases:

 template <typename Iter, typename F> void map(Iter first, Iter last, F && f) { // ... use f(*first) ... } 

Please note that in this case we do not use std::forward , since we use f as a genuine link, and not just pass it through to another place. In particular, we are not allowed to move from f if we are still planning on using it.

+7
source share

All Articles