Using C++ classes like function that may be defined in several different locations

298 views Asked by At

Between C++0x, C++03 TR1 and boost some things like function and bind can be defined in 3 different places depending on the compiler, eg for VC pre VC9 feature pack you have the boost versions, then you get them in but in the std::tr1:: namespace, and VC10 moves that to just the std:: namespace.

Currently my existing code uses the older boost versions in the boost:: namespace exclusivly, however since for many of my applications and libaries all the boost stuff I used is now in tr1 and C++0x, id like if possible remove the boost dependency from those, while retaining backwards compatibility with older compiler versions.

However I'm not sure on how to make my code locate, include and then be able to access the correct versions :( One thing I have considered is using macros like _MSC_VER to see if the compiler includes the classes I want, (falling back to tr1 and then to boost as needed) and then use the "using somenamespace::someclass;" stuff to move the classes in question into the std:: namespace.

The problem is it seems that in some cases this might break stuff, and I'm not even sure how to tell if VC9 has its feature pack or SP1 installed or not :( I'm also not sure on a tidy way to do it, perhaps provide my own functional.hpp that does the required "magic"?

The main thing is I want to start writing my code for the new standards, but in a way that it will still work with minimal effort on older compilers.

3

There are 3 answers

1
dappawit On

From your post it seems like you are primarily concerned about VC++. If thats the case, then I think using preprocessor defines based on the _MSC_VER is probably the most straight forward solution. As you hinted at, just find out what versions were first to provide the various features and include the appropriate header.

As far as how to access them in your code, I would just use several typedefs that are set to different types depending on the included header. If the boost, tr1, and C++0x versions of the libraries provide the same (or similar enough) interfaces, this should "just work". Although, if the type is a class template, plain typedefs won't work, and you'll have to resort to a #define.

Sometimes straight forward is good. It may not be worth making it too complicated. (If you want to support more than just VC++, you will probably have to get complicated.)

Perhaps something like this (as a first thought):

#ifdef _MSC_VER
  #if _MSV_VER >= VERSION_WITH_CXX0X
    #include <function>
    #define FUNCTION_NAMESPACE std
  #elif _MSV_VER >= VERSION_WITH_TR1
    #include <tr1/function>
    #define FUNCTION_NAMESPACE std::tr1
  #else
    #include <boost/function.hpp>
    #define FUNCTION_NAMESPACE boost
#else
  #error The current compiler is not supported.
#endif

void func();

FUNCTION_NAMESPACE::function<void ()> funcobj(func);

Although I don't like using a #define to get the namespace, I can't think of another way off the top of my head. I bet there is one, though.

4
James McNellis On

Since you're already using Boost, consider using the macros that Boost.Config provides to test for potentially supported features. Specifically, take a look at the BOOST_HAS_TR1_* macros and the BOOST_NO_* macros.

Note that you have to check for individual features, since not all implementations of TR1 and C++0x support all features of those specs.

5
ildjarn On

Boost.TR1 already does this for you – it has compiler/version detection logic to use your compiler's TR1 implementation if it's available for your platform, or use the various relevant Boost libraries to emulate TR1 if not:

This library does not itself implement the TR1 components, rather it's a thin wrapper that will include your standard library's TR1 implementation (if it has one), otherwise it will include the Boost Library equivalents, and import them into namespace std::tr1.