Is C++ 0x/TR1 safe to use when portability matters? - c++

C++03 is lacking some things I'd love to use: std::shared_ptr, std::function and std::bind.
We can't fully switch to C++11, because the project needs to work with older libstdc++ versions. I know that this stuff is in Boost as well, but we cannot use that for other reasons.
Hence we started to use C++ 0x/TR1, which is supported by all the compiler versions we currently use. But we're having some trouble with it:
There's very little information about what of TR1 is implemented in which version of Clang/MSVC/GCC
I cannot figure out what the -std=c++0x switch does in Clang, compiles fine without it
I'm not sure what namespaces to use, e.g. std::tr1::shared_ptr vs std::shared_ptr
So, the question: Is C++ 0x/TR1 safe to use when portability matters? Is it implemented in all major compilers? Should I worry about proprietary toolchains etc.? Are we better off sticking to C++03?

TR1 is an experiment made by the C++ standards committee. The purpose of the experiment is to get field experience for libraries, with the hope of standardizing them in a future standard.
TR1 is not a normative standard.
The spec of TR1 specifies the use of namespace std::tr1. The reason things were not put into namespace std is to allow the committee more freedom in modifying the TR1 specification on the way to standardization. And yes, modifications were made in places when most of TR1 was standardized in C++11.
The TR1 document begins with these words:
This technical report is non-normative. Some of the library components
in this technical report may be considered for standardization in a
future version of C++, but they are not currently part of any C++
standard. Some of the components in this technical report may never be
standardized, and others may be standardized in a substantially
changed form.
The goal of this technical report it to build more widespread existing
practice for an expanded C++ standard library. It gives advice on
extensions to those vendors who wish to provide them.
Most, but not all of TR1, was widely implemented in in the 2005 time frame across gcc and MSVC. The llvm libc++ was developed after the TR1 time frame and was targeted straight at the new C++11 standard, which moves many TR1 components into namespace std, and makes them normative (required by a standard).
Clang is known to be used with both llvm libc++ and gcc's libstdc++.
I do not know which implementations of the std::lib you need to be portable among. If all of the places you need to port to implement TR1, it is safe, otherwise it is not. But TR1 is not a normative standard. C++98, C++03 and C++11 are normative standards.
Checked just for fun, and it turns out libcxx used in Emscripten is
the issue, not Clang 3.2.
I have coached many, many project owners on how to make their code which uses TR1 portable across libstdc++ (has TR1) and libc++ (has C++11). libc++ places those TR1 components that were standardized into C++11 in namespace std as specified in C++11. It does this even when -std=c++03. This was done as a transition aid. libc++ does not try to be a C++03 conforming library. It's life starts with C++11.
libc++ has a version number macro called _LIBCPP_VERSION. If this macro is defined after include'ing a std-header, you are using libc++, else you are not. So you can write code like this:
#ifdef _LIBCPP_VERSION
// using libc++
#include <memory>
typedef std::shared_ptr<MyType> MyTypePtr;
#else // !_LIBCPP_VERSION
// not using libc++
#include <tr1/memory>
typedef std::tr1::shared_ptr<MyType> MyTypePtr;
#endif // _LIBCPP_VERSION
Note that you must have first included some std-header for _LIBCPP_VERSION to get defined or not. If you need to gratuitously include a std-header to see if _LIBCPP_VERSION gets defined, use:
#include <ciso646> // detect std-lib
C++98/03/11 specify <ciso646> to do absolutely nothing. So it is very cheap to include. The libc++ implementation of this header does nothing but define _LIBCPP_VERSION.
Once done, your code can now easily switch among libc++ and other libraries which implement TR1.

Instead of trying to make TR1 work on all your different compilers, I would just take the boost code (header-only) and copy-paste it into your own project (since you can't use boost directly for whatever reason). The boost versions are well supported and debugged, and will work consistently across any C++98 compiler that is supported by boost.

Related

c++17 polyfills and boost

Some of the new features that have been added to the recent ISO C++ standards were originally part of boost.
This naturally raises the question of guidelines for writing portable code.
Is there a canonical way to portably use new language features when using an older version of the standard?
If you are already using boost should you continue to use the boost versions or the versions in C++17 or the experimental versions?
How far should you go in trying to be portable?
I am surprised not to find this question as a FAQ somewhere.
Shouldn't there be something about this in the core guidelines, the boost FAQ and or as an ISO committee paper?
There seem to be questions about individual features but less considering the wider view.
For example:
C++11 Polyfills
Aliasing boost::variant or std::variant not compilable
How to correctly shim functionality into std?
There are several projects that provide polyfills.
Boost is not the only option, though it may be the most common and comprehensive.
There are others, for example:
https://github.com/tcbrindle/cpp17_headers
https://www.reddit.com/r/cpp/comments/5oz3zj/c_shims_library/
https://abseil.io/about/philosophy
You can import the appropriate version with using clauses but this is risky as it masks semantic differences
see also:
From boost to std::experimental and furthermore c++17
You might consider using feature test macros
and create headers like "cxx17/optional.hpp" containing:
#ifdef __cpp_lib_experimental_optional
#include <experimental/optional>
namespace cxx17
{
using std::experimental::optional;
}
#elif __cpp_lib_optional
#include <optional>
namespace cxx17
{
using std::optional;
}
#else
#include <boost/optional.hpp>
namespace cxx17
{
using boost::optional;
}
#endif
However this still papers over semantic differences.
In some cases the boost libraries deliberately differ from the standard.
You also have to consider that there is no such thing as portable code
only code that has been ported. You cannot guarantee your code will work
unless you have actually tested it in each environment.
If you attempt to make your code portable like this and have no intention
of running it on those environments its just a YAGNI (you ain't gonna need it).
Using the feature test macros shows you're clever but it could be considered noise if they aren't used.
If you are using boost already it seems safe to assume you can continue using it
and leave it to boost (and the boost maintainers) to detect whether you are using C++17 or a TS
and act according. Unless you have a lot of resources you can assume that
the boost libraries are more portable than your code.
A good thing to do is to document intent.
If you just want to make life easier for future maintainers but you are stuck using
C++11 for now you might consider just doing (in cxx17/import_optional.hpp):
#include <boost/optional.hpp>
namespace cxx17
{
using boost::optional;
}
and using the cxx17 namespace to indicate that you wish to use C++17
but can't yet. This also implies that you consider deviations between boost and the ISO standard a bug
for your project. Other users may just prefer the boost version.
(consider for example What are the differences between std::variant and boost::variant?)
This applies mainly for pure library extensions.
For changes to the language itself you can sometimes emulate them using macros. This can be ugly so it may be better to stick to a given standard.
This should probably be a community wiki but I will wait in case a more learned guru comes up with a better answer.

What is the purpose of llvm::make_unique?

In llvm's compiler implementation tutorial (e.g. here) llvm::make_unique is used. What is the reason they aren't using std::make_unique? I wasn't able to find any clear documentation on this.
TL;DR;
LLVM is written using C++11 conforming code while std::make_unique is a C++14 feature. So if they want make_unique they need to implement it.
Details
If we go to the LLVM Coding Standards the C++ Standard Versions section says:
LLVM, Clang, and LLD are currently written using C++11 conforming code, although we restrict ourselves to features which are available in the major toolchains supported as host compilers. The LLDB project is even more aggressive in the set of host compilers supported and thus uses still more features. Regardless of the supported features, code is expected to (when reasonable) be standard, portable, and modern C++11 code. We avoid unnecessary vendor-specific extensions, etc.
We can see from cppreference that std::make_unique is a C++14 feature. If they want to use make_unique then they can't use the std version.
We can see from a recent llvm-dev discussion that moving to C++14 is still an open subject.

How well does boost use c++11?

Boost is essentially a c++03 library (which stimulated the c++11 standard). I'm contemplating of using some boost libraries (those that are not implemented in c++11). If I'm using c++11, does boost compile (there may be issues with non-copyable but movable objects)? and how well is boost making use of the c++11 features (variadic templates are an obvious thing to use [by some boost libraries] instead of much of the boost MPL)? (I couldn't find this amongst the boost FAQ).
Boost is moving towards using C++11 features.
But one thing to remember is that boost is not "a library", but rather a collection of libraries. Some of them (for example boost::array) probably won't ever be updated to use many c++11 features. Why should it, when you have std::array in the standard (which was based on boost::array?)
On the other hand, Boost would like to remain useful for people who are still using C++03.
Note: Even though I write as if "Boost" is some monolithic entity, there are lots of people who contribute to boost and they have many different opinions. ;-)
To see how well various boost libraries work with C++11 compilers, you can check out the Boost Testing web page.
C++11 was made do be as backwards compatible as possible. Unless boost is using reserved keywords that are new to C++11, there is no reason I know of why it shouldn't compile just fine with the new standard.

What will happen to namespace tr1 when c++ xx is approved?

I'm writing some stuff using the tr1 namespace in VS2008. What will happen when C++xx becomes ratified? Has this happened before with other C++ revisions? Will the tr1 stuff still work or will I have to change all of my include? I realize that I'm making the very large assumption that this ratification will someday occur. I know that most likely none of you work for MS or contribute to GCC, but if you have experience with these kinds of changes, I would appreciate the advice.
std::tr1 will become part of std in C++1x (std::tr1::shared_ptr becomes std::shared_ptr, etc). std::tr1 will continue to exist as long as that compiler claims to implement TR1. At some point your compiler may drop that claim, and drop std::tr1 as a result. This probably will never happen.
std::tr1 has already been "copied" into namespace std in Visual Studio 2010 Beta (via a using directive)
The Wikipedia entry for C++0x says "A large part of the new libraries are defined in the document C++ Standards Committee's Library Technical Report (called TR1), which was published in 2005. Various full and partial implementations of TR1 are currently available using the namespace std::tr1. For C++0x they will be moved to namespace std. However, as TR1 features are brought into the C++0x standard library, they are upgraded where appropriate with C++0x language features that were not available in the initial TR1 version. Also, they may be enhanced with features that were possible under C++03, but were not part of the original TR1 specification."
tr1 is not part of any standard (the paper it is shorthand for never was accepted) - it's just a convention that some compilers provide. They will almost certainly go on providing it long into the future.

Using GCC's C++0x mode in production?

Is anyone using the GCC 4.4.0 C++0x support in production? I'm thinking about using it with the latest MinGW, but I'm not sure if it's mature enough.
I'm interested in:
TR1 support
auto
initializer lists
IMHO, TR1 support and auto are safe to use. In the case of auto it was one of the first features to be included into the standard and is a relatively small change to the language. I would therefore have no problem using it.
I would be a bit more hesitant about using initializer lists. On some other forums (eg. comp.lang.c++.moderated) there are questions about their behaviour and its possible that they may change closer to the release of the standard.
I'm not using GCC 4.4.0 C++0x support in production but I'm using the TR1 features with the help of the Boost Library http://www.boost.org/.
The Boost Library is well tested and often used in production environments. If you convert to the C++0x standard later the only thing you have to do is changing your include Directives http://www.boost.org/doc/libs/1_40_0/doc/html/boost_tr1.html.
In my opinion it's currently better to use the Boost Library until the standard is finished. It's a much more compiler independent way.
MinGW simply won't compile with '-std=c++0x'. Strange enough, '-std=gnu++0x' works. Anyway it seems buggy and I won't count on it.