I've been working for a good while in keeping a level of forwards- and backwards-compatibility in my C++ programs, until I eventually had to make a library toolkit out of it, which I'm preparing for release has already been released. In general, so long as you accept that you won't get "perfect" forwards-compatibility neither in features (some things just can't be forward-emulated) not in syntax (you probably will have to use macros, alternate namespaces for some things) then you are all set.
There's a good lot of features that can be emulated in C++03 in a level that is enough for practical use - and without all the hassle that comes with eg.: Boost. Heck, even the C++ standards proposal for nullptr
suggests a C++03 backport. And then there's TR1 for example for everything C++11‑but‑we've‑had‑previews‑for‑years stuff. Not only that, some C++14 features like assert variants, transparent functors and optional
can be implemented in C++03!
The only two things that I know that can not absolutely be backported are constexpr and variadic templates.
With regards to the entire matter of adding stuff to namespace std
, my view of it is that it doesn't matter - at all. Think of Boost, one of the most important and relevant C++ libraries, and their implementation of TR1: Boost.Tr1. If you want to improve C++, make it forwards compatible with C++11, then by definition you are turning it into something that is not C++03, so blocking yourself over a Standard that you intend to avoid or leave behind anyway is, simply put, counterproductive. Purists will complain, but by definition one needs not to care about them.
Of course, just because you won't be following the (03) Standard after all doesn't mean you can't try to, or would be going to gleefully go around breaking it. That's not the point. So long as you keep very careful control as to what is added to the std
namespace, and have a control of the environments where your software is used (ie.: do testing!), there should not be any untratable harm at all. If possible, define everything in a separate namespace and only add using
directives to namespace std
so that you are not adding anything there beyond what "absolutely" needs to go in. Which, IINM, is more or less what Boost.TR1 does.
Update (2013): as the request of the original question and seeing some of the comments that I can not add to due to lack of rep, here is a list of C++11 and C++14 features and their degree of portability to C++03:
nullptr
: fully implementable given the official Committee's backport; you'll probably have to provide some type_traits specializations as well so that it is recognized as a "native" type.
forward_list
: fully implementable, though allocator support relies on what your Tr1 implmenentation can provide.
- New algorithms (partition_copy, etc): fully implementable.
- Container constructions from brace-sequences (eg.:
vector<int> v = {1, 2, 3, 4};
): fully implementable, though wordier than one would like.
static_assert
: near-fully implementable when implemented as a macro (you'll only have to be careful with commas).
unique_ptr
: near-fully implementable, but you'll also need support from calling code (for storing them in containers, etc); see the below though.
- rvalue-references: near-fully implementable depending on how much you expect to get from them (eg.: Boost Move).
- Foreach iteration: near-fully implementable, syntax will differ somewhat.
- using local functions as arguments (for eg.: transform): near-fully implementable, but syntax will differ enough - for example, local functions are not defined at the call site but right before.
- explicit conversion operators: implementable to practical levels (getting the conversion made explicit), see Imperfect C++'s "explicit_cast"; but integration with language features such as
static_cast<>
might be near-impossible.
- argument forwarding: implementable to practical levels given the above on rvalue-references, but you'll need to provide N overloads to your functions taking forwardeable arguments.
- move: implementable to practical levels (see the two aboves). Of course, you'd have to use modifier containers and objects to profit from this.
- Scoped allocators: Not really implementable unless your Tr1 implementation can assist it.
- multibyte character types: Not really implementable unless your Tr1 can support you. But for the intended purpose it's better to rely on a library specifically designed to deal with the matter, such as ICU, even if using C++11.
- Variadic argument lists: implementable with some hassle, pay attention to argument forwarding.
noexcept
: depends on your compiler's features.
- New
auto
semantics and decltype
: depends on your compiler's features - eg.: __typeof__
.
- sized integer types (
int16_t
, etc): depends on your compiler's features - or you can delegate to the Portable stdint.h.
- type attributes: depends on your compiler's features.
- Initializer list: Not implementable to my knowledge; however if what you want is to initialize containers with sequences, see the above on "container constructions".
- Template Aliasing: Not implemementable to my knowledge, but it is an unneeded feature anyway, and we've had
::type
in templates forever
- Variadic templates: Not implementable to my knowledge; the close is template argument defaulting, which requires N specializations, etc.
constexpr
: Not implementable to my knowledge.
- Uniform initialization: Not implementable to my knowledge, but guaranteed default-constructor initialization can be implemented ala Boost's value-initialized.
- C++14
dynarray
: fully implementable.
- C++14
optional<>
: near-fully implementable so long as your C++03 compiler supports alignment setups.
- C++14 transparent functors: near-fully implementable, but your client code will likely have to explicitly use eg.:
std::less<void>
to make it work.
- C++14 new assert variants (such as
assure
): fully implementable if you want asserts, near-fully implementable if you want to enable throws instead.
- C++14 tuple extensions (get tuple element by type): fully implementable, and you can even get it to fail to compile with the exact cases described in the feature proposal.
(Disclaimer: several of these features are implemented in my C++ backports library that I have linked above, so I think I know what I'm talking about when I say "fully" or "near-fully".)