1

I'm moving part of a threading library from C++03 to C++11, yet I'd like to keep it compatible with Boost, as an option for users who don't have C++11 compilers. Since C++11 STL and Boost 1.54 basically have the same interface (at least for the part I'm interested in), it would be nice to have something like this:

#ifdef USING_BOOST
#define NAMESPACE boost
#else
#define NAMESPACE std
#endif

typedef NAMESPACE::mutex MyLibrary::Mutex;
typedef NAMESPACE::condition_variable MyLibrary::ConditionVariable;
...

The problem comes with templates, e.g. unique_lock. A better approach could be this:

#define TYPEDEF(WHAT, AS) typedef LIBPREFIX::WHAT AS

#define TYPEDEF_T(WHAT, AS)                 \
    template <typename T>                   \
    struct AS                               \
    {                                       \
        typedef LIBPREFIX::WHAT<T> type;    \
    };

TYPEDEF( thread, Thread );
TYPEDEF( mutex, Mutex );
TYPEDEF( condition_variable, ConditionVariable );

TYPEDEF_T( lock_guard, LockGuard );
TYPEDEF_T( unique_lock, UniqueLock );
TYPEDEF_T( shared_ptr, SharedPtr );

However I'll have to use it this way:

LockGuard<Mutex>::type lock(...);

E.g. I don't like having to write ::type all the times.

Also, I'd like to override the make_shared function, i.e. mapping it as follows:

MyLibrary::MakeShared<T> --> NAMESPACE::make_shared<T>

where NAMESPACE is either 'std' or 'boost'. I guess that something like

#define USING(WHAT) using NAMESPACE::WHAT
USING( make_shared );

is not a viable option... right?

Overriding the entire boost namespace is not a solution, as other parts of Boost could be used in the code. What would be the best way to achieve this?

Thanks!

rippeltippel
  • 369
  • 1
  • 7
  • 15
  • Be aware that the thread libraries in boost and C++11 have important differences in behaviour: see http://stackoverflow.com/a/7242294/231299 – beerboy Sep 10 '13 at 04:04

3 Answers3

4

You can simply import the appropriate names into your namespace by using declarations:

namespace MyLibrary {

#ifdef USING_BOOST
  using boost::thread;
  using boost::unique_lock;
  using boost::make_shared;
#else
  using std::thread;
  using std::unique_lock;
  using std::make_shared;
#endif

}

This works for all names: classes, functions and templates.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • 1
    My main concern about this solution is putting 'using' clauses in a header file, as it may cause name conflicts with other namespaces. – rippeltippel Sep 09 '13 at 10:54
  • 1
    @rippeltippel: How could these `using`s cause more problems than your typedefs? They both introduce names within your `MyLibrary` namespace. – Xeo Sep 09 '13 at 11:43
  • 1
    @rippeltippel What Xeo says. `using` declarations (and `using` directives) put identifiers into the scope where they appear. The infamous `unsing namespace std;` discouraged in header files is a problem because it's used in the global namespace. – Angew is no longer proud of SO Sep 09 '13 at 12:00
  • @rippeltippel - good instinct; you've internalized the many criticisms you've seen of `using namespace std;`. These `using` declarations deal with particular names; they're not the sledgehammer that `using namespace std;` is. – Pete Becker Sep 09 '13 at 13:45
1

Use namespace aliases:

#ifdef USING_BOOST
namespace mt = boost;
#else
namespace mt = std;
#endif

Now you can refer to mt::condition_variable and the compiler will see the one from the appropriate namespace.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
0

Wouldn't the simplest option be to carry on using boost? That would avoid making unnecessary work for yourself. Failing that, why not just typedef for the types that you'd like to select from one library or the other:

namespace foo {
#ifdef USING_BOOST
    typedef boost::mutex       mutex;
    typedef boost::scoped_lock mutex_lock;
#else
    typedef std::mutex       mutex;
    typedef std::unique_lock mutex_lock;
#endif
}

foo::mutex myMutex;
RobH
  • 3,199
  • 1
  • 22
  • 27