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

3

8

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.

Heyde answered 2/3, 2011 at 0:34 Comment(4)
+10 - I too really want to know how to do this. (for both g++ and msvc)Helper
Note that things haven't just been moved around: there are differences among various versions of Boost, TR1, and C++0x. There are bugs in some TR1 implementations that aren't present in Boost. Just swapping one namespace for another may work 99% of the time, but in a large code base, you're bound to run into some problem. (As just one example, the technique used in the VC9 feature pack to implement safe bool doesn't work when you compile with /clr and use it in C++/CLI code. That was a fun bug to track down.)Tithonus
Though I'm not 100% sure, _MSC_FULL_VER might serve.Boylan
@James Well I guess I can fix those as I come to them, it's better than at least 3 sets of conditional compiling everywhere I use these things :)Heyde
S
8

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.

Scots answered 2/3, 2011 at 1:8 Comment(5)
Will tr1 use the full C++0x implementions where available? Also as I said id like to make boost not be a dependency where no longer needed, espically for my library code.Heyde
In general, I don't believe so; but in VC++ 2010's case, its C++0x implementation is really just its TR1 implementation using'd into namespace std. I.e., it will use the C++0x implementation for VC++ 2010 if not for other toolsets.Scots
@Fire: not depending on Boost is not a worthwhile goal for a C++ project to pursue.Chongchoo
@mmutz: I disagree. All projects should endeavour to minimize dependencies- if those dependencies are provided as Standard, then the Standard functionality should be used.Proulx
@DeadMG: I cannot agree with you. This is the mindset that leads to the horrible NIH syndrome that plagues so many C and C++ projects.Chongchoo
W
3

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.

Weiss answered 2/3, 2011 at 0:42 Comment(1)
Well there is the "namespace myfunctional{using std::tr1::function;}" I guess. Just not keen on moving a lot of stuff into my namespaces when ultimatly it will be in std::. Just feels wrong kind of like how doing "namespace mynamespace{using namespace std;}" does.Heyde
T
0

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.

Tithonus answered 2/3, 2011 at 1:1 Comment(4)
I guess I could do that, although if I can eliminate the boost dependency on compilers that fully support what I want then that will be good. Chances are as far as the more advanced features go like rvalues, auto, etc that when I start using those I'll remove support for older compilers from the new library versions anyway. I'll dig through the boost headers and see where the TR1 macros are coming from, since I assume boost stupports VC9 without its service pack?Heyde
Boost supports VC++ from 2003 onwards.Scots
Is it no longer VC6? I'm sure i sure a lot of stuff for VC6 in the boost code. Anyway my point is that for VS2008 and VS2010 where I dont need boost at all, id rather not have boost at all in my libaries.Heyde
The last version of Boost to officially support VC6 was 1.34.1. Some libraries may still work with VC6, but it hasn't been a supported toolset for years now.Scots

© 2022 - 2024 — McMap. All rights reserved.