August 19th, 2026
heartlike2 reactions

On wrapping a callable in a lambda that just calls it with the same parameters

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.

Topics

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

4 comments

Sort by :
  • Billy O'Neal 56 minutes ago

    Also sometimes used to convert function calling conventions rather than the language-level parameters 🙂

  • R Samuel Klatchko 3 hours ago · Edited

    A related issue is is wrapping a simple function in a lambda. Consider:

    <code>

    and wanting to use square with modify_and_print. I've seen developers who will reflexively use a lambda <code> when it's perfectly legal to pass the function directly <code>.

    That said, sometimes the lambda is useful. If you add an overload for square, the lambda will continue to compiler but the function pointer would need to be cast to choose the correct overload.

    Read more
    • BCS 20 minutes ago

      Came here looking for that last point. A lambda taking auto and forwarding it to a function symbol is about the only correct way to pass an “overlord set” as an argument.

      (C++ more or less requires thinking in terms of overload sets but then sadly provides very limited support for actually doing anything with them but calling them. In fact I’m not actually sure that term is a thing according to the standard.)

  • LB 5 hours ago

    We had an intern once who noticed that some of the lambdas they were writing needed to be used across multiple files. They declared global const std::function objects and initialized them from the lambdas. I converted those to normal functions when I saw it…