Programming

Monday, July 23, 2012

Portable development with C++11

The C++11 standard has nearly been around for a whole year, and it really is a very worthwhile upgrade. Code is generally quite a bit cleaner, especially with things like the auto keyword, lambdas, for loops, uniform initialization and the like. I recently completed a project using C++11 (the purpose was to gain some more hands-on experience with C++11), then I needed to convert it back to C++03, and it was painful to go back.

But all is not perfect with C++11. We are very much reliving the bad old days of C++ (2000-2005), where many compilers claim standards compliance, or at least parts of it, but the reality there are many quirks which don't work even if they should. You only discover the quirks when you run into them. You can't rely on the compiler to "teach you" what the correct behaviour is (as I certainly did when learning C++), because usually the compiler is at fault.

It gets even worse when you try to get the same code to compile on multiple platforms and compilers, because you end up working around N different compilers, when they should all be supporting the same language. As a result, you end up programming to the lowest common denominator, or using #if to select different code depending on the compiler, which is far from ideal.

Another problem is the "cross platform" might include some older compilers, whose C++11 support is more limited.

Things which went well:
  • The thread libraries <thread> and <mutex> worked flawlessly and identically on all platforms. Some platforms were more forgiving than others, but being more stringent is OK in my book.
  • Boost interface is often identical to C++11. So with a #if you can choose which implementation to use, and write code to compile for both. 
Annoyances:

  • No sleep_for on GCC Macports. Possibly a configuration error on Macports, however it needs preprocessor workarounds which is downright annoying. A standard should mean the standard, the whole standard and nothing but the standard.
  • GCC does not support C++11 by default. Obviously this is for backwards compatibility, however if you are going to upgrade your compiler, then there can be a switch to enable backwards compatibility. I really hope that this default is changed (e.g. 5.0).
  • Variadic templates in lambdas not supported in GCC.
  • Bind only partially working in Visual Studio.
  • Syntax checkers and auto-indenters don't work with C++11 very well.
  • noexcept, =default, =delete are not supported on Visual Studio 2011.
  • CMake does not know about C++11 or C++0x, and cannot tell the compiler in a portable way to use C++11. Therefore you need to specify compiler switches manually.
  • XCode has made the switch to clang, and its version of GCC is stuck at 4.2 which is ancient.
Things which are downright aggravating:
  • No variadic templates at all in Visual Studio 11.
  • Internal compiler error (compiler crash) using lambas on Clang 3.1. No I have not filed a bug report.
In summary then, GCC was clearly the best, even on some older versions (e.g. 4.6), followed by Clang, the Visual Studio 2011 trailing. I really look forward when C++11 moves out of "beta" status, as it's currently the compilers which are holding everyone back.