Welcome. It's been a while. 2020, right?

You might remember that two or three years ago I experimented with migrating to C++11, and I did some preparation (a short recap is in the first part of this post). Well, we’re finally doing it for real. This post lists a few bumps you might find and tells you how to avoid them.

This comes after some setup work. During the past year, I deprecated compilers that wouldn’t be able to compile C++11 code; and in the latest release, I removed support for the last of them (Visual C++ 2012). After which, I started the actual work of taking what I learned from the experiment and migrating the library.

As usual, I’m making an effort to keep the whole thing backward-compatible. You shouldn’t have to modify your own code to work with the next version of the library—not right away, at least. Depending on your code, you might have to change a couple of configuration flags to enable full backward compatibility. Similar to what happens when we deprecate some class or function, those flags are going to be available for the next few releases: this will give you some time to do the required changes. (Oh, in case I wasn’t clear: these changes are being made now in the git repository and will be in version 1.22, so you don’t have to worry about them yet. I’m posting about them now while I still remember what I did.)

So without further ado, here’s your migration guide.

Check your compilation flags

For instance, clang on Mac OS X still compiles in C++03 mode by default with some C++11 extensions but not all. Make sure you pass at least the -std=c++11 flag to clang and gcc to enable newer features. You can pass later standards too, if you want: the library also compiles correctly in both C++14 and C++17 mode.

Out with auto_ptr, in with unique_ptr

If you used a recent compiler to compile the library, there’s a chance that it warned you about std::auto_ptr being deprecated. We already had a configuration flag allowing you to switch to std::unique_ptr already (here is the GitHub pull request that introduced it), and now it’s enabled by default so that QuantLib uses std::unique_ptr.

If you relied on some QuantLib function explicitly returning std::auto_ptr, your code might not compile with next release.

Short-term fix for backward compatibility:

You can add the --disable-std-unique-ptr flag when you run configure, or you can undefine QL_USE_STD_UNIQUE_PTR in ql/userconfig.hpp if you’re not running it. This causes the library to use std::auto_ptr again.

Long-term fix:

Change your uses of std::auto_ptr to std::unique_ptr. If you used the QL_UNIQUE_OR_AUTO_PTR macro we provided, you should be ok for the time being. In the long run, that macro will disappear and we’ll use std::unique_ptr explicitly.

Out with Disposable, in with copy elision and move semantics

The Disposable class was an attempt to implement move semantics in C++03 code. This is no longer necessary; classes in the library that needed it now have move semantics, and in any case most compiler nowadays implement RVO and NRVO and Disposable would get in the way of that. Therefore, it is now defined as

template <class T>
using Disposable = T;

that is, an alias to the underlying type.

If you wrote functions or methods overloaded on T and Disposable<T>, those functions will not compile now since the two types are the same.

Short-term fix for backward compatibility:

You can add the --enable-disposable flag when you run configure, or you can define QL_USE_DISPOSABLE in ql/userconfig.hpp if you’re not running it. This causes the library to use the old implementation of Disposable again.

Long-term fix:

Remove Disposable<T> from your code. If you used it to implement a pseudo-move constructor or assignment, define a proper one by using an rvalue reference instead, so for instance

Array(const Array&);
Array(const Disposable<Array>&);

will become

Array(const Array&);
Array(Array&&) QL_NOEXCEPT;

(oh, yes, move constructors and assignment should be declared as noexcept to allow more optimizations. We have to use a QL_EXCEPT macro in the library because it’s one of the few features Visual Studio 2013 doesn’t support.)

Out with virtual, in with override

In C++11, virtual method should only be marked with virtual in the base class that declares them. In derived classes that define them, they should be marked as override or final; this allows compilers to possibly detect and warn against unintentional overrides. In order to automate this change, I added a clang-tidy check to the GitHub actions we’re running on each push to the repository.

This shouldn’t give you problems in compilation, but it might cause warnings such as inconsistent-missing-override in clang or suggest-override in gcc. You might be bothered by them—possibly because you’re using -Werror (good practice, folks).

Short-term fix:

Disable those particular warnings if your code triggers them.

Long-term fix:

You can do as we did and get clang-tidy to fix that for you. Our automated workflow is here: it will check the code, make fixes and open a pull request with them. It relies on this script and this configuration file, both in the QuantLib repository.

I’ll be adding more gotcha to the blog as I use more C++11 features; stay tuned. If you have comments or experiences on the above, the right place to post them is probably the QuantLib mailing list so they reach and benefit the largest possible number of people.

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.