Suppose you have a function that accepts a lambda and wants to use it when calling another function. I’ve seen people wrap the lambda inside another lambda:
template<typename Lambda>
bool Widget::QueueToWorkerThread(Lambda&& lambda)
{
CreateWorkerThreadIfNeeded();
return m_dispatcherQueue.TryEnqueue(
[lambda = std::forward<Lambda>(lambda)]() { lambda(); });
}
But there’s no point in wrapping a lambda inside another lambda if you are just calling the inner lambda with the same parameters as the outer one. You can use the inner lambda’s function call operator directly.
template<typename Lambda>
bool Widget::QueueToWorkerThread(Lambda&& lambda)
{
CreateWorkerThreadIfNeeded();
return m_dispatcherQueue.TryEnqueue(
std::forward<Lambda>(lambda));
}
My guess is that some people don’t realize that a lambda is not a special entity in the C++ language, where if somebody says that a function accepts a lambda, they think that it means that you must literally pass a lambda.
In C++, a lambda is just syntactic sugar for a class with a function call operator. And if you already have a class with a function call operator, there’s no need to wrap it inside another class with the same function call operator.
Wrapping a lambda is basically doing this:
template<typename Lambda>
bool Widget::QueueToWorkerThread(Lambda&& lambda)
{
CreateWorkerThreadIfNeeded();
struct wrapper {
wrapper(Lambda&& lambda) :
m_lambda(std::forward<Lambda>(lambda)) {}
auto operator()() const { return m_lambda(); }
private:
const std::remove_reference_t<Lambda> m_lambda;
};
return m_dispatcherQueue.TryEnqueue(
wrapper(std::forward<Lambda>(lambda)));
}
There’s no need to introduce the extra level of indirection. The incoming lambda is already in the form you want. Just use it.
Bonus chatter: Wrapping a lambda is significant if there is a transformation on the parameters, such as cocercing them to a particular type or forcing them to be passed by value.
0 comments
Be the first to start the discussion.