Easier To Use, And More Expressive

One of the goals for each evolutionary increment in C++ is to decrease the probability of an average programmer from making mistakes by supplanting “old style” features/idioms with new, easier to use, and more expressive alternatives. The following code sample attempts to show an example of this evolution from C++98/03 to C++11 to C++14.

In C++98/03, there were two ways of clearing out the set of inner vectors in the vector-of-vectors-of-doubles data structure encapsulated by MyClass. One could use a plain ole for-loop or the std::for_each() STL algorithm coupled with a remotely defined function object (ClearVecFunctor). I suspect that with the exception of clever language lawyers, blue collar programmers (like me) used the simple for-loop option because of its reduced verbosity and compactness of expression.

With the arrival of C++11 on the scene, two more options became available to programmers: the range-for loop, and the std::for_each() algorithm combined with an inline-defined lambda function. The range-for loop eliminated the chance of “off-by-one” errors and the lambda function eliminated the inconvenience of having to write a remotely located functor class.

The ratification of the C++14 standard brought yet another convenient option to the table: the polymorphic lambda. By using auto in the lambda argument list, the programmer is relieved of the obligation to explicitly write out the full type name of the argument.

This example is just one of many evolutionary improvements incorporated into the language. Hopefully, C++17 will introduce many more.

Note: The code compiles with no warnings under gcc 4.9.2. However, as you can see in the image from the bug placed on line 41, the Eclipse CDT indexer has not caught up yet with the C++14 specification. Because auto is used in place of the explicit type name in the lambda argument list, the indexer cannot resolve the std::vector::clear() member function.

8/26/15 Update – As a result of reader code reviews provided in the comments section of this post, I’ve updated the code as follows:

Like this:

Related

With C++03 you could use std::for_each with std::mem_fun_ref(&std::vector::clear). I tend to think that’s better than all the others except the C++11 one that uses range-based for. Although this sort of “functional” approach can get hard to read for anything more complex. A separate functor, a lambda, or ranged-based for can quickly become a better choice.

Ranged-based for is great except when you want to iterate over less than the full range. I really wish C++11 had included some adaptor classes to help make ranged-based for more flexible.

C++ 11 option A has the tersest and most readable loop header (no unneeded std::begin and std::end) and loop body (no repeated types, no syntactic “noise” from lambda functions). When would the other new variations be useful?

I find the main cases where I don’t use ranged-based for—as hinted at in my previous comment—are when I don’t want to iterate over the entire range. There are tricks to doing that with ranged-based for. e.g. A simple Range class that takes two iterators and has begin & end member functions. But since they aren’t standard, such an idiom is less likely to be immediately recognized by the reader.

I do understand that it is an academic example, but I think it would be a much better example if you called the function something like “clear_inner_vectors” and didn’t clear the outer vector in the function.

My fear is that a novice seeing this example would mistakenly assume that _vecVecDouble.clear() would not destruct the inner vectors, and then write code based on that mistaken assumption.