Tell me more ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I work on a large software application that must run on several platforms. Some of these platforms support some features of C++11 (e.g. MSVS 2010) and some don't support any (e.g. GCC 4.3.x). I expect this situation to continue for for several years (my best guess: 3-5 years).

Given that, I would like set up a compatibility interface such that (to whatever degree possible) people can write C++11 code that will still compile with older compilers with a minimum of maintenance. Overall, the goal is to minimize #ifdef's as much as reasonably possible while still enabling basic C++11 syntax/features on the platforms that support them, and provide emulation on the platforms that don't.

Let's start with std::move(). The most obvious way to achieve compatibility would be to put something like this in a common header file:

#if !defined(HAS_STD_MOVE)
namespace std { // C++11 emulation
  template <typename T> inline T& move(T& v) { return v; }
  template <typename T> inline const T& move(const T& v) { return v; }
}
#endif // !defined(HAS_STD_MOVE)

This allows people to write things like

std::vector<Thing> x = std::move(y);

... with impunity. It does what they want in C++11 and it does the best it can in C++03. When we finally drop the last of the C++03 compilers, this code can remain as is.

However, according to the standard, it is illegal to inject new symbols into the std namespace. That's the theory. My question is: practically speaking is there any harm in doing this as a way of achieving forward compatibility?

share|improve this question
1  
Boost already provides quite a bit of this, and already has code to use new features when/where available, so you might be able to just use what Boost provides, and be done with it. Of course, there are limitations -- most new features were added specifically because library-based solutions aren't adequate. – Jerry Coffin Apr 3 '12 at 20:38
yes, I am thinking specifically about those features that can be implemented at the library level, not the syntactical changes. Boost doesn't really address the issue of (seamless) forward compatibility. Unless I'm missing something... – mcmcc Apr 3 '12 at 21:24
Gcc 4.3 already has a good handful of C++11 features, the Rvalue-references being probably the most important. – Jan Hudec Apr 4 '12 at 6:38
@JanHudec: You're right. Poor example. In any case, there are other compilers that definitely don't support the syntax (e.g. whatever version of IBM's C++ compiler we have). – mcmcc Apr 5 '12 at 13:46

3 Answers

This is fundamentally impossible. Consider std::unique_ptr<Thing>. If it was possible to emulate rvalue references as a library, it would not be a language feature.

share|improve this answer
I did say "to whatever degree possible". Clearly some features will have to be left behind #ifdef's or not used at all. std::move() happens to be one that you can support the syntax (albeit not the functionality). – mcmcc Apr 3 '12 at 21:15
1  
Actually the rvalue references proposal mentions a library-based solution! – Jan Hudec Apr 4 '12 at 6:41
More specifically, it is possible to implement move semantics for particular class in C++03, so it should be possible to define std::unique_ptr there, but it's some other features of rvalue references cannot be implemented in C++03, so std::forward is not possible. The other thing is that the std::unique_ptr won't be useful, because the collections won't use the move semantics unless you replace them all. – Jan Hudec Apr 4 '12 at 7:16
@JanHudec: It isn't possible to define unique_ptr. Look at the failings of auto_ptr. unique_ptr is practically the textbook example of a class whose semantics were fundamentally enabled by the language feature. – DeadMG Apr 4 '12 at 19:48
@DeadMG: No, it's not unique_ptr that was fundamentally enabled by the language feature. It wouldn't be very useful without that feature though. because without perfect forwarding it wouldn't be usable in many cases and perfect forwarding does require that feature. – Jan Hudec Apr 5 '12 at 12:30
  1. Gcc started introducing C++11 (still C++0x at that time) in 4.3. This table says it already has rvalue references and some other less used features (you have to specify -std=c++0x option to enable them).
  2. Many additions to standard library in C++11 were already defined in TR1 and GNU stdlibc++ provides them in std::tr1 namespace. So just do appropriate conditional using.
  3. Boost defines most of the TR1 functions and can inject them into the TR1 namespace if you don't have it (but VS2010 does and gcc 4.3 does as well if you use GNU stdlibc++).
  4. Putting anything in std namespace is an "undefined behaviour". That means the specification does not say what will happen. But if you know that on particular platform the standard library does not define something, just go ahead and define it. Just expect that you will have to check on each platform what you need and what you can define.
  5. The proposal for rvalue references, N1690 mentions how to implement move semantics in C++03. That could be used to substitute unique_ptr. However, it would not be too useful, because it relies on collections actually using the move semantics and the C++03 ones obviously won't.
share|improve this answer
1  
You're correct about GCC but unfortunately, I also have to support other (non-GCC) compilers. Your #4 bullet is at the heart of the question I'm asking. #5 is interesting but I'm not looking to support move semantics (the copy optimization) on these older platforms but rather just "std::move()" as a compilable syntax. – mcmcc Apr 5 '12 at 15:00

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. 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. For example, unique_ptr, static_assert, nullptr, forward_list, initializer lists, move semantics, and, depending on the compiler, decltype and right angle brackets, can all be emulated in C++03 in a level that is enough for practical use. Heck, even the C++ standards proposal for nullptr suggests a C++03 backport. And TR1 for example for everything C++11‑but‑we've‑had‑previews‑for‑years stuff. 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 stalling yourself over what one Standard says while you aim for the other One, is kind of counterprductive. Any purist will vomit and denounce you to their religion's followers, but they would as well for goto, or even for break/continue; no point worrying about them.

Of course, just because you won't be following the Standard after all doesn't mean you can't try to, or would be going to gleefully go around breaking the Standard. 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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.