Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When using templates to support functor as arguments, what qualifier should I use?

Consider this code:

template<class F>
void foo1(F f) { f(); }

template<class F>
void foo2(F const& f) { f(); }

template<class F>
void foo3(F&& f) { f(); }

Which version of foo should I use? foo1 is what I see most "in the wild" but I fear that it might introduce copies that I don't want. I have a custom functor that is kind of heavy to copy so I would like to avoid that. Currently I'm leaning towards foo3 (as foo2 would disallow mutating functors) but I'm unsure about the implications.

I'm targeting C++11.

like image 280
Artificial Mind Avatar asked Jul 01 '18 13:07

Artificial Mind


1 Answers

I’d actually prefer foo3 over foo1 (though the body should be std::forward<F>(f)();)

foo3 will cause type F to be deduced to the type that lets you perfectly forward the argument due to reference collapsing. This is useful, as you won’t make copies of anything by default, and can maintain the value category (lvalue vs rvalue) if you decide you want to forward the functor to something that does want a copy of it.

In general, the first form (foo1) is fine if your function is going to store its own copy of the functor, but the third form (foo3) is better for forwarding (using) arguments.

I also recommend Scott Meyers’ excellent post about universal references, as well as this related Stack Overflow question.

like image 122
John Drouhard Avatar answered Nov 19 '22 17:11

John Drouhard