How to handle evolving c++ std:: namespace? e.g.: std::tr1::shared_ptr vs. std::shared_ptr vs. boost::shared_ptr vs. boost::tr1::shared_ptr
Asked Answered
E

3

9

For the code I am currently working on, we sometimes need to compile on some older systems with older compilers (e.g.- we run sims on an older IBM BlueGene/L, who's support contract dictates some quite old C++ compiler). The code itself makes use of shared_ptrs, and was originally written to use std::tr1::shared_ptr. When compiling on the old BlueGene machine, I quickly realized that it doesn't have a tr1:: implementation, and so I switched to boost::shared_ptr. Turns out there is also a boost::tr1::shared_ptr. Now that the code is being used more widely outside of our research group, portability is becoming even more important.

What is a (the?) best practice for handling these sorts of evolving standard library issues in a large-ish codebase? I am assuming that in the new C++11 standard, shared_ptr will no longer be in the tr1 namespace, which adds another potential: std::shared_ptr, however I am guessing widespread support for this will be a ways off. I'd like to be using the latest standard if possible, but need to maintain portability. Should I just stick with boost?

Exhalation answered 17/8, 2011 at 15:37 Comment(3)
There are already compilers where std::shared_ptr is available, like VC2010 and recent versions of g++. If you need to support a multitude of different compilers, sticking with boost is probably the easiest though. :)Malamute
Just because shared_ptr will be added to namespace std:: doesn't mean it will be removed from namespace std::tr1::. I know that gcc/libstdc++ will maintain both going forward. In fact, I'm sure visual studio will be the same.Undeceive
I think if you look around, support for std::shared_ptr is very broad across most compilers in the last two years at least. I would stick with std:: first, then look for std::tr1:: then try boost in that order.Undeceive
V
9

To detect which namespace the shared_ptr is in, you need something like autoconf -- this is the reason why autoconf was created (detecting platform/compiler variations). You can do this with:

AC_LANG(C++)

AC_MSG_CHECKING([for std::shared_ptr])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
    [[#include <memory>]]
    [[std::shared_ptr<int> have_shared_ptr;]])
], [
    AC_MSG_RESULT([yes])
    AC_DEFINE_UNQUOTED([HAVE_STD_SHARED_PTR], 1, [Define to 1 if you have the `std::shared_ptr' class.])
], [
    AC_MSG_RESULT([no])
    AC_DEFINE_UNQUOTED([HAVE_STD_SHARED_PTR], 0, [Define to 1 if you have the `std::shared_ptr' class.])
])

Repeat for std::tr1::shared_ptr, boost::tr1::shared_ptr and boost::shared_ptr.

You can then create a shared_ptr.hpp file that is something like:

#include <config.h>

#if defined(HAVE_STD_SHARED_PTR)
    namespace ptr = std;
#elif defined(HAVE_STD_TR1_SHARED_PTR)
    namespace ptr = std::tr1;
#elif defined(HAVE_BOOST_SHARED_PTR)
    namespace ptr = boost;
#elif defined(HAVE_BOOST_TR1_SHARED_PTR)
    namespace ptr = boost::tr1;
#else
#   error No shared_ptr found.
#endif

... which you can then use as:

ptr::shared_ptr<int> pointer(new int(5));
Vocative answered 17/8, 2011 at 16:52 Comment(1)
Your second comment in the autoconf example should be invertedDecorous
C
8

Partial answer to your question

boost::tr1 is invented exactly for the standard library implementations that don't have a tr1. To quote the documentation from here:

The TR1 library provides an implementation of the C++ Technical Report on Standard Library Extensions. 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

Countertenor answered 17/8, 2011 at 15:40 Comment(1)
Thank you very much for the tip- I had no idea that boost::tr1 imported into std::tr1. Having boost::tr1 now makes much more sense to me. Cheers!Exhalation
G
1

Why not have some special compile time checking? Kind of:

#if __GNUC__ > 3
     #define BOOST boost::
#else
     #define BOOST boost::tr1::
#endif

BOOST shared_ptr<...> ...

You can look up in the boost libraries, they have a lot of compiler/version-detection code.

See this question for details about the macros, especially this link: http://predef.sourceforge.net/.

Gilles answered 17/8, 2011 at 15:43 Comment(2)
I do similar except I use std::tr1 and std:: instead.Undeceive
I actually used to do something like that because it was the easiest thing to do. When it started getting more tangled (some compilers have changes in TR1 support across minor versions, for example) I decided to just use std in library code and let the user adapt his environment, he knows it better than I do.Vacancy

© 2022 - 2024 — McMap. All rights reserved.