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
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, whi开发者_高级运维ch 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?
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));
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
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/.
精彩评论