Welcome back.

A couple of posts ago, I mentioned that two new pull requests made it possible to use std::function and std::bind in QuantLib instead of the corresponding classes from Boost. Here are a few more details.

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

    #if defined(QL_USE_STD_FUNCTION)
    #include <functional>
    #else
    #include <boost/function.hpp>
    #endif

    namespace QuantLib {

        namespace ext {

            #if defined(QL_USE_STD_FUNCTION)
            using std::function;
            #else
            using boost::function;
            #endif

        }

    }

and I replaced boost::function with ext::function in the library code. A configure switch optionally sets the QL_USE_STD_FUNCTION define, thus effecting the change to std::function. The same went for 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 --enable-std-bind.

Of course, it wasn’t all as simple as sketched above.

The first problem came even before starting the convention. Our use of boost::function goes way back; in fact, back to ancient times where not all compilers could parse the boost::function<R(T)> syntax. Because of this, Boost provided an alternate syntax boost::function1<R,T> (with similar function0 or function2 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 `vector<function<R(T)> >.

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 if (f.empty()), which works for boost::function but not for the std version. Moving to 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, as in:

    typedef Real(C::*T)(Real) const;
    ... ext::bind(T(&C::m), this, _1) ...

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

    ext::bind(std::multiplies<Real>(),
        ext::bind(&CLVModelPayoff::operator(), &clvModelPayoff, _1),
        ext::bind<Real>(boost::math::pdf<chi_squared_type, Real>,
            dist, _1) )

to

    class integrand {
        ...
        Real operator()(Real x) const {
            return payoff(x) * boost::math::pdf(dist, x);
        }
    };

Next difference: the std implementation of bind also specifies an inner namespace std::placeholders to contain the placeholders _1, _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 namespace ext::placeholders that contains _1 etc. in the std case and that remains empty in the boost case. Writing

    using namespace ext::placeholders;
    ...
    ext::bind(f, _1);

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 the std classes, and should fail as soon as old syntax enters the build.

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.

Subscribe to my Substack to receive my posts in your inbox, or follow me on Twitter or LinkedIn if you want to be notified of new posts, or subscribe via RSS if you’re the tech type: the buttons for all 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.