This technique is sometimes used to handle transitive dependencies on header only libraries. It is not generally a best practice.
The problem: I am writing a C++ library. I put all of my declarations into a namespace foo { ... }
. So users of my library can avoid that namespace. But what happens when I want to use another library in my library? Let's call the second library bar
. If I use the bar library normally, I am exposing both the foo
and bar
namespaces to the users. My dependency is not invisible, and could break code of my users.
If the bar
library makes its namespace configurable, I can avoid that by moving it into a foo::detail::bar
namespace.
At first, it might seem like I could simply include a header within a namespace:
namespace foo { namespace detail {
#include <bar.h>
} }
However, headers are generally written to assume that they are included at the top-level. In particular, expect this to break the standard library as used through that header. This will also fail if bar is not a header-only library, because the object code will be compiled into a different namespace.
Using macros is the preferable solution. A single namespace macro that takes values such as foo::detail
is insufficient prior to C++17, so that separate macros for declaration start/end and the actual namespace are necessary. E.g. see this example in Hydra.
However, these techniques suffer from various problems and restrictions.
The header files typically still contain include guards, so that each compilation unit can import a library under at most one namespace. In practice, this is not a big restriction.
If a library is imported under multiple namespaces, any objects declared by that library are duplicated. This may or may not be desired.
If the library with variable namespaces is not a header-only library, then the object code for that library must also be compiled into the correct namespace. This requires you to define the necessary macros in your build system.
The core problem that these macros are trying to solve is that C++ does not have a proper module system. How are other languages addressing potentially clashing namespaces?
Java has a package naming convention based on domain names, so no name clashes between organizations should arise. E.g. If you hold example.com
, then you should put the foo library into the com.example.foo
namespace.
Rust and Perl have one central library index (Crates and CPAN, respectively). Just don't use any namespaces that could be reserved there. Additionally, Rust does not make the namespace of a crate visible unless you import it, whereas the C++ one-definition-rule is global.
Python has relative imports. A well-written module does not need to know its absolute location.
Hopefully, C++ modules will adopt a reasonable solution when they finally arrive.
The tuple example you linked to is fundamentally different: the purpose of that library is to patch the standard library if it doesn't provide a tuple of its own. Here, the namespace configurability is only provided to optionally place the tuple into a different namespace.
To summarize: configurable namespaces have legitimate uses when building libraries for libraries. Most C++ code should not bother with this, especially not application code.
#ifndef #define
is traditionally used to make sure symbols are only defined once, and thrust doesn't appear to use macros to define its namespaces. It's unclear to me what benefits your sample code provides.LIB_NS
namespace might heavily change the semantics to anonymous namespaces. Be aware of that.