Yan Zhu
Yan Zhu

Reputation: 4356

boost::shared_ptr and std::shared_ptr co-existence

We all know that both boost and c++11 has support for shared_ptr. Some compiler has support for c++11 while some doesn't. I would like to write my code so that when compiler support c++11 shared_ptr, it uses std::shared_ptr; when it doesn't, use boost::shared_ptr. What is the common/best practice for that?

Let me confine the discussion to GCC but not to particular version.

Upvotes: 7

Views: 1323

Answers (2)

ComicSansMS
ComicSansMS

Reputation: 54787

You can just pull them into a custom namespace

#ifdef HAS_STD_SHARED_PTR
    #include <memory>
    #define SHARED_PTR_NAMESPACE std
#else
    #include <boost/shared_ptr.hpp>
    #define SHARED_PTR_NAMESPACE boost
#endif

namespace my_namespace {
     using SHARED_PTR_NAMESPACE::shared_ptr;
     using SHARED_PTR_NAMESPACE::make_shared;
}

#undef SHARED_PTR_NAMESPACE

The HAS_STD_SHARED_PTR flag needs to be set by the build environment. CMake provides several mechanisms for detecting such features and newer C++ implementations also provide feature test macros for quick and easy detection of newer features.

Upvotes: 3

syam
syam

Reputation: 15089

C++0x / C++11 availability

The only way I am aware to detect whether GCC is using C++0x/C++11, as of today, is to check for the predefined macro __GXX_EXPERIMENTAL_CXX0X__:

#ifdef __GXX_EXPERIMENTAL_CXX0X__
    // C++11 code
#else
    // C++03 code
#endif

Note that this may change in the future (hence the EXPERIMENTAL part of the macro).

Edit: in fact there's a better way I didn't know of until @stephan pointed it out in a comment:

16.8/1 [cpp.predefined]

The following macro names shall be defined by the implementation:

__cplusplus

The name __cplusplus is defined to the value 201103L when compiling a C ++ translation unit.157

157) It is intended that future versions of this standard will replace the value of this macro with a greater value. Non-conforming compilers should use a value with at most five decimal digits.

So I guess you could do:

#if defined(__cplusplus) && (__cplusplus >= 201103L)

But I fear this wouldn't work with pre-standard C++0x GCC versions. So I'd probably use both __GXX_EXPERIMENTAL_CXX0X__ and __cplusplus together:

#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined(__cplusplus) && (__cplusplus >= 201103L))

C++0x / C++11 compatibility

However this may not always be enough to just detect whether C++0x/C++11 support is enabled: C++11 support has changed a lot throughout GCC versions, not only at the core language level but at the library level too.

My best bet would be to find which minimal GCC version you find acceptable for C++11 support and combine the above tests with a GCC version test, eg:

#if (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ >= 5)) // for GCC 4.7+

Switching between boost and std

Now, to switch between boost::shared_ptr and std::shared_ptr it's a bit cumbersome because C++03 doesn't support templated typedefs. I for one would wrap the required definitions in a template struct:

#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined(__cplusplus) && (__cplusplus >= 201103L))) \
        && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ >= 5))
    template<typename T>
    struct my_shared_ptr {
        typedef std::shared_ptr<T> type;
        // you may also want to forward make_shared etc, this is left as an exercise
    };
#else
    template<typename T>
    struct my_shared_ptr {
        typedef boost::shared_ptr<T> type;
        // you may also want to forward make_shared etc, this is left as an exercise
    };
#endif

my_shared_ptr<int>::type ptr(new int);

Edit: (again) whoops I just noticed @ComicSansMS's way of importing the right shared_ptr with a simple non-template using directive. Dunno why I didn't think about that.

Still, I stand with the way I described of detecting C++0x/C++11 on GCC.

Upvotes: 4

Related Questions