9

A similar question has been asked before, but I'm still confused. The STL, I believe, exclusively passes by value, as passing by reference might have consequences in a multi-threaded environment. Say, when two or more threads are executing a mutable lambda. I currently use a universal reference when I just want to invoke a lambda:

template <typename F>
inline void invoke(F&& f)
{
  f();
}

This binds to any function object, just like a const& would, but maybe it's a bad idea for inlining. Is a lambda passed by copy easier to inline by the compiler? I'd like the passed lambdas to be as "inlinable" as possible.

Community
  • 1
  • 1
user1095108
  • 14,119
  • 9
  • 58
  • 116

1 Answers1

3

Think of a lambda as a small object with a function call operator:

int foo = 1000;
auto f = [=]() ->int { return foo; };

is somewhat equivalent to:

class FooLambda {
    int foo;
  public:
    FooLambda(int foo) : foo(foo) {}
    int operator()(){ return foo; }
};
// ...
int foo = 1000;
FooLambda f(foo);

So you see, the function body itself can be inlined if it is seen in the same translation unit as it is called (and possibly if not by some smarter compilers). Since your invoke is a template, it knows the actual type of the lamdba, and you don't force it to jump through function-pointer hoops, which a big inhibitor of inlining.

Taking the callable object by value or reference in invoke determines whether the captured variables are local to the function body or not, which can make a difference if it means they will be in cache.

BoBTFish
  • 19,167
  • 3
  • 49
  • 76