C++11: Sum Across a Collection of Objects Using a Lambda or a Range-Based For Loop

I’m always disappointed when my Google search doesn’t turn up useful results on the first page. Often, an answer to a C++ question takes me to a StackOverflow page, or to a cplusplus page, where I usually find what I want. This time I didn’t find what I want on the first page (the stackoverflow link wasn’t quite it), hence this blog post.


Image source: jfgormet, Flickr

I’ve just started a series on test-focused learning (TFL) for the new C++11 features. I’m jumping the gun a little here since I’ve not yet covered lambdas (or auto, or the range-based for, or rvalue references), but I wanted searchers to have (what I think is) a better answer on the first page.

The story: Iterate a vector of objects, adding into a sum by dereferencing a member on each object, then return the sum from a function.

Here’s the declaration for the Item class:

class Item {
public:
   Item(int cost) : cost_{cost} {}
   int Cost() { return cost_; }
private:
   int cost_;
};

Here’s the assertion (I coded this test-first, of course):

ASSERT_THAT(
   TotalCost({Item(5), Item(10), Item(15)}),
   Eq(5 + 10 + 15));

You can get this test to pass in three statements using the range-based for loop.

int TotalCost(vector<Item>&& items) {
   int total{0};
   for (auto item: items) total += item.Cost();
   return total;
}

That’s clean and simple to understand, explanation of syntax barely needed.

Here’s the implementation using accumulate and a lambda.

int TotalCost(vector<Item>&& items) {
   return accumulate(items.begin(), items.end(), 0,
     [] (int total, Item item) { return total + item.Cost(); });
}

That’s it. If you’re not familiar with accumulate (I wasn’t, hence my Google search), it takes a range, an initial value, and a function. If you’re not familiar with using lambdas to declare functions:

  • [] declares that the lambda requires no capture of other variables
  • between () is the parameter list for the arguments that accumulate passes to the function
  • between the {} is the function’s implementation

Which do you prefer (or neither), and why?

This entry was posted in C++, TDD, test-driven development, test-focused learning, TFL, unit testing and tagged , , , , . Bookmark the permalink.

5 Responses to C++11: Sum Across a Collection of Objects Using a Lambda or a Range-Based For Loop

  1. It should be + rather than += in

    return accumulate(items.begin(), items.end(), 0,
    [] (int total, Item item) { return total + item.Cost(); });

    also the += happens to be legal and have a side effect that does not matter in this case.

    In a toy sequential program, I don’t really care how the sum is implemented; it’s O(n) anyway. In a real program summing a huge data set, of course we would want to get parallel speedup by means of the standard map/reduce abstraction. We might not want to have a vector at all, but a parallel vector instead, for example.

  2. jlangr says:

    Thanks Franklin,

    Good catch on the +=, that was inadvertent (copied quickly from the code for the range-based for loop). Fixed.

    The article is focused on readability/understanding of the C++11 features. Either construct is still applicable in non “toy” programs–not all “real” programs require that level of optimization.

    -J-

  3. I remember downloading STL using ftp from HP in 1994 over a modem Internet connection and being all excited about it, as a software engineer using C and C++ at the time, but also at the same time I was getting into functional programming. I do have to confess to having a warm fuzzy feeling about now being able to use the lambda in C++11 if were still actively programming in C++ these days. Not having to manually lambda-lift and create structs to simulate closures is going to be a big win for working C++ programmers, I predict.

  4. christi parks says:

    I am not a programmer but I have this C language subject this session and have to prepare for it. What all topics should be covered in it?
    And has anyone studied from this course http://www.wiziq.com/course/2118-learn-how-to-program-in-c-language of C tutorial online?? or tell me any other guidance…
    would really appreciate help

  5. Bret Kuhns says:

    I definitely prefer the more functional style version over the imperative loop. Looking a bit into the future, it’ll only get better with standard range-based algorithms in C++17 and the new lambda changes proposed for C++14…

    return accumulate(items, 0, [] (int total, const Item& item) total + item.Cost());

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>