Sunday, January 13, 2013

C++11 Lambdas: how many statements can I squeeze in one line of code?

Learning a little C++11 by porting some old Boost ASIO programs to it. Lambdas are one of the new features - they have an interesting syntax for letting you define in great detail how you want to capture variables from the enclosing scope.  (How did C++ get lambdas and closures before Java by the way?).

You can combine lambdas with STL and fancy new builtin types like std::thread to get code like this:


    std::transform(
      m_ioServiceVector.begin(),
      m_ioServiceVector.end(),
      std::back_inserter(threadVector),
      [] (IoServicePtr pIOService)
      {
        return ThreadPtr(
          new std::thread([=] ()
            {
              pIOService->run();
            }));
      });

What on earth does this do?  Short summary is we've created a vector of boost::asio::io_service objects (m_ioServiceVector) and we want to create a thread to call run() on each io_service.  We also want to hang on to pointers to the std::thread objects we create in a vector named threadVector.

In more detail, this code:
1. Loops through m_ioServiceVector.  Each item in m_ioServiceVector is a std::shared_ptr (IoServicePtr is a typedef).  
2. For each io_service, call a lambda that creates a new std::thread and returns a std::shared_ptr to it (ThreadPtr is a typedef).  This lambda captures no variables, so we use the empty brackets ("[]").
3. Each thread runs its own lambda, which just calls run() on the boost::asio::io_service.  This lambda needs to capture a copy of pIOService since it runs in a new thread (potentially after the enclosing pIOService has gone out of scope), so we use "[=]".
4.  The std::back_inserter puts the ThreadPtrs created into a vector named threadVector.

How many lines of code is this?  Counting non-comment lines, it's 12. Counting semicolons, it's 3. But really this is all just a single function call to std::transform, so you could certainly argue it's just 1 line of code.  I can't wait to see what SLOC counters do with this.