Leaving C++03: more STL classes
A couple of posts ago, I
mentioned that two new pull requests made it possible to use
std::bind in QuantLib instead of the
corresponding classes from Boost. Here are a few more
But first, a PSA. I’m thinking of revising these posts about my Leaving C++03 experiment and of publishing them as a book on Leanpub. If you want that to happen, please go to https://leanpub.com/goingtocpp11 and show your interest. Thanks.
Back to the subject of the post. The change was similar to the one
that I previously described for
shared_ptr and its related
classes; that is, I added a file with code like
and I replaced
ext::function in the library
code. A configure switch optionally sets the
define, thus effecting the change to
std::function. The same went
boost::bind (which also took
boost::cref along for the ride),
and since we’re starting to have quite a few of these switches, I also
added a global configure switch
--with-std-classes as a shortcut for
--enable-std-pointers --enable-std-unique-ptr --enable-std-function
Of course, it wasn’t all as simple as sketched above.
The first problem came even before starting the convention. Our use
boost::function goes way back; in fact, back to ancient times
where not all compilers could parse the
syntax. Because of this, Boost provided an alternate syntax
boost::function1<R,T> (with similar
classes for different number of arguments) and used to suggest its use
for greater compatibility. The need for this is gone, but we still
had a few instances of those classes in the code; and of course
there’s no such alternate syntax for
std::function, so they had to
go and be replaced by their more modern equivalent.
Unfortunately, this breaks backwards compatibility. The older
boost::function1<R,T> class is convertible to
boost::function<R(T)>, but it’s not the same class (at least, not in
C++03; in C++11, it could be aliased to the newer class via the
using syntax). And we had a couple of methods using
vector<function1<R,T> >, which is not convertible to
This is a problem. Since version 1.0, I tried to avoid breaking changes and to uphold the promise that if you code against a version of QuantLib, your code will still compile against later versions. Usually, I can manage it by overloading methods and deprecating old ones so that they could be phased out in future releases; but I didn’t have a chance here. One of the methods had the old class in the return type, over which we can’t overload.
In the end, I went ahead with the change. I’ll document the break of compatibility in the release notes for next version, and hope that not many people had inherited the affected classes (which are not fundamental ones).
The conversion had a few other glitches, but nothing major. One was
that we had used in a couple of places the syntax
which works for
boost::function but not for the
if (!f), which works for both, fixed the problem.
Another was that, if a method
m if a class
C is overloaded,
boost::bind(&C::m, this, _1) will select the correct overload but
std::bind won’t—at least in the implementation shipping with
my compiler. To fix this, I had to specify the overload explicitly,
In a particularly hairy case involving the template class
boost::math::pdf, I couldn’t get
std::bind to work and I had to
write a function object instead. I don’t complain, though, as I feel
that this improved readability; the code went from
Next difference: the
std implementation of
bind also specifies an
std::placeholders to contain the placeholders
_2 and so on, while in the Boost implementation the placeholders are
in the same namespace as
bind. Both can be accommodated by adding a
ext::placeholders that contains
_1 etc. in the
case and that remains empty in the
boost case. Writing
works in both cases.
Also, once everything was working, I went the extra mile and removed a
couple of uses of Boost.Lambda. On the one hand, it used
_1 for a
different object, which I felt to be confusing; and on the other hand,
removing them goes in the direction of eventually phasing out most
Boost classes in favor of C++11 features.
Finally, we need to make sure that explicit references to
boost::function, or other code not compatible with both
implementations, won’t come crawling back in the library. This is
checked by The same daily Travis CI run that checks that our C++11 code
stays integrable with the newest changes on the master branch; it uses
std classes, and should fail as soon as old syntax enters the
So far, I didn’t find the time (or, indeed, the motivation) to research, install and moderate a comment system. If you want to reach out with suggestions or questions, please send me a tweet or an email. I’ll report on your feedback in future posts.
Follow me on Twitter or LinkedIn if you want to be notified of new posts, or subscribe via RSS: the buttons for that are in the footer. Also, I’m available for training, both online and (when possible) on-site: visit my Training page for more information.