Effective reuse is an important part of good software engineering. To demonstrate how much better off you can be by using standard library algorithms instead of handcrafting your own, let’s reconsider the previous question to demonstrate how many of the problems could have been avoided by simply reusing what’s already available in the standard library.

Problem

JG Question

1. What is the most widely used C++ library?

Guru Question

2. How many of the pitfalls in GotW #2 could have been avoided in the first place, if only the programmer had replaced the explicit iterator-based for loop with:

(a) a range-based for loop?

(b) a standard library algorithm call?

Demonstrate. (Note: As with GotW #2, don’t change the semantics of the function, even though they could be improved.)

1. If you take the question like “what library is used in most C++ projects”, it’s probably iostreams. If you take it like “what library’s functions are called most of all”, it’s STL.
2. As I’ve already proposed range-for-based loop, here it is again:

What do we get from both?
1. We do not need to memoize end(emps);
2. No possible ++ issues (hey, nobody can guarantee he never wrote postfix ++ accidentally);
3. We’ve got and employee& inside the body rather than some_fancy_iterator.

What do we get from range-for?
It soo much more clear what’s happening with less code. Not all algorithm combinations can be expressed with this loop though.

But even if I’m restricting to STL like containers in the C++11 version, it is highly preferable than repeating the type of what is stored in emps (perhaps const decltype(*begin(emps))& would be better ? I think it lacks of clarity but it would have the great advantage of working on any kind of container, STL like or not).

With this, I am able to change the container type, or even the type in the container (as long as it has a name() method and an addr member attribute) from one and only one point (here the function declaration) without changing at all the meaning and the validity of the code.
This increases code reusability.

For the difference between RBFL and lambda+algo :
* RBFL is simpler : no extra variables, no extra code. But it needs either a comment or a longer read time later.
* lambda+algo is more expressive : the code itself says it wants to *find* the *emp* *whose name* is *name* and *return* *its addr* *if you found one* or *”” as the default value*. Could you even be more expressive on what this code does in a comment poorly paraphrasing the code ?

I’m a part of those people (I’m Mikhail Belyaev with wordpress messing my name for every second comment) and I would say it rocks. I even have my own set of range-based algorithms in my current project (as well as a function that wraps any pair of iterators into a range-for-enabled structure). Too bad we don’t have ‘em in the stl yet.
On the other hand, some complex loopy operations will still be expressed with range-for much better.

In code review I would probably complain that with the find_addr function you get an empty string if:
– the employee does not exist, _and_
– the employee exists but its adress has not been set yet (e.g. addr was default constructed to an empty string).

If the function is required I’d recommend using boost::optional for the return type. However I would _strongly_ recommend that the best way to improve this function is not to write it in the first place. Is just a one-liner call to find_if. And by using find_if directly the semantics of not found are crystal clear.

@Gabriel Garcia used std::optional up there. I still think the best thing is not to write this function at all.

@bilbothegravatar Herb mentioned the GotW’s are covering C++14 now. That lambda syntax is a new feature of C++14. It uses both generic/polymorphic lambdas (note the const auto& parameter), and the abbreviated syntax that makes the curly braces and return statement optional (the return becomes assumed).

@bilbothegravatar Also, the Range Study Group is targeting a TS after C++14. They fixed some wording for C++14 to remove some roadblocks for the TS, hopefully making it all the easier to adopt in C++17. Judging by your gravatar, I’ll assume you know to use boost.range for now ;-)

Well may be this sound strange for some peoples here but STL is not used all the time.
In some projects I was working on STL usage was a bad sign and was not really permitted.
Boost look like a great library but it is much too big and many times slow (compiler time and runtime).

IMHO range based for loop is shorter and better as find_if.
And less dependencies on STL :)

@Olaf What about if we’re skimming through code, trying to get a grasp on what it does. Let’s say my eyes catch this line:

for (auto& e : emps) {

All this tells me is that you’re looking through `emps`. If I instead see this line:

auto it = find_if(emps, [&](auto& e) e.name == name );

Then, well… the story’s over. I see exactly what it’s doing. Even if I don’t read the lambda, I know you’re looking for something in `emps` and whatever’s found, if any, is stored in `it`. I know this from reading only part of one line of code.

The advantage of using STL algorithms is about information density, IMO.

You don’t know whether employee::employee(std::string) or employee::operator==(…) exist, and even if they do, it is rather unlikely that two employees are only identified by their name and find() will most-likely return end().

@Olaf I said information density, not functionality. There are lots of things you can do to pack more functionality in less code, and the majority of those techniques are a bad idea because they reduce readability. Whereas STL algorithms give the reader more information in a tight space than imperative for/while loops.

Steve Teixeira, MSFT 13 May 2013 12:17 PM #
@Tom Kirby-Green, C++11 support remains a very high priority. However, we are targeting the next VS release for additional C++11 support (you’ve already seen the beginnings of this in the CTP). It is problematic for us to add new language features in VS Updates because doing so creates a situation whereas two VS2012 developers may not be able to share code with one another due to different levels of language support in different point-releases.

I totally agree with Bret Kuhns that find_if is clearer than a raw loop. A raw loop is an implementation of the algorithm, not it’s name. We have abstractions to help us understand our code, let’s user them.

I seriously hope that Steve is just woefully uninformed, and we will in fact be receiving VC++ updates prior to VS.Next. That assertion is completely ridiculous (see VS2008 vs. VS2008 SP1 for a direct contradiction).

@Olaf van der Spek: The other guys already told about find_if being self documenting: To discover that this code is doing a search, you only need to read the function name in the find_if case, but for range for, you need to check the loop body, and if the condition is more complex than this, you might need to take more than 0.1s to discover that it is a search. It’s also less error prone (no silently compiling mistakes e.g. if( name = emp.name() ) ).

And if you are into unit testing, you would also like that find_if version has only 2 branches (I’m not really into testing STL implementation), while the range-for version has 4 (depending on how you define branches), so you need more test cases for 100% code coverage.

I really hope that ‘expression lambdas’ don’t get added to a future version of C++. Consider:

int i = 1, j =1;
auto f = [](auto &i, auto &j) i++; j++;

Unless we’re going to adopt a policy of “never let a lambda parameter name shadow a variable in scope”, then expression lambda syntax is just a trap for the unwary. Let’s learn the lesson from ambiguous expressions in

if

and

for

statements, and require

{}

in situations where there’s no benefit to allowing them to be elided.

Adding (more) syntactical ambiguity to the language for the ‘benefit’ of typing two characters fewer is not a net win, in my opinion.