Leaving C++03: compiler compatibility so far
In this post, a quick check: with what compilers does our current C++11 branch work?
The baseline is, of course, that the compiler should be from 2011, or more probably a bit later: those of you that were around at that time will remember that compilers didn’t catch up as fast as they do now (yes, kids these days have it easy). Thanks to the magic of Docker, I didn’t have to retrieve and compile old versions of gcc and clang, either: between the official images of Ubuntu Trusty (a distribution from 2014), Debian Jessie (initially from 2015, but kind of conservative) and Centos 7.0 (also 2014, and also updated cautiously) I could throw together a decent set of compiler versions. Microsoft makes older versions of Visual C++ available, too.
As I suspected, compilers from 2011 and 2012 were not yet up to the
task. gcc 4.6.3 didn’t support static data-member initialization, the
override keyword, or defaulted destructors (and for good measure,
its C++11 mode was still called
-std=c++0x); clang 3.0 did better,
but couldn’t use initializer lists to return values; and Visual C++
2012 choked on most of the above and the
After a couple of years, though, the picture got better. Both gcc 4.8
and clang 3.3, from 2013, could compile the branch successfully, and
so can all later versions—with a couple of caveats. One is
that, by changing compiler and thus library version, sometimes I’d
find that our code was relying on a standard header that was included
only indirectly. (I’m sure you’re a better person; I confess that,
when the code compiles, I don’t always check that it includes headers
for every feature it uses.) The other is that, even though the
compilers had caught up, Boost sometimes didn’t; in particular, I had
errors with the version of Boost included with older distribution
boost::hash_map was not specialized for
Switching to a more recent version of Boost cured the problem. As for
Visual Studio, the 2015 version was successful; the 2013 version,
however, joined gcc 4.7 in the “almost, but not quite” category (I
suspect that clang 3.1 or 3.2 might belong there, too, but I didn’t
find a distribution carrying those versions).
gcc 4.7.2 (released in September 2012) failed with a curious error which I didn’t stop to investigate. Here it is, reduced to a few lines of code:
The above fails to compile with:
test.cpp:9:13: error: looser throw specifier for 'virtual D::~D()' test.cpp:4:13: error: overriding 'virtual B::~B() noexcept (true)'
upon seeing which, I promptly closed the terminal window and walked away.
Visual C++ 2013 choked on all uses of
std::bind (spewing multi-line
errors about the expression losing const-volatile qualifiers when
called), but I’m not overly worried about that; in the following of
this experiment, I’ve been meaning to replace them all with lambdas
anyway. What worried me more was that it also didn’t support the
noexcept keyword, which would be nice to have since
it has beneficial effects on performance.
If we want to keep the
noexcept specifiers (which I’d like) and if
we want to support VC++ 2013 (which I’d also like, since it’s not so
old as compilers used in finance go) we might need to hide the keyword
QL_NOEXCEPT macro that can be conditionally defined as
noexcept or nothing.
We’ll see, I guess—but the first step would be to remove those
bind calls. I’ll tell you about this another time, though.
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.