In his book The C++ Programming Language (third edition) Stroustrup teaches to define individual components in their own namespace and import them in a general namespace.
For example:
namespace array_api {
struct array {};
void print(const array&) { }
}
namespace list_api {
struct list {};
void print(const list&) { }
}
namespace api {
using array_api::array;
using list_api::list;
}
I looks interesting, but I have never seen this approach used in practice.
Why is this technique is almost never used?
The problem with putting using namespace in the header files of your classes is that it forces anyone who wants to use your classes (by including your header files) to also be 'using' (i.e. seeing everything in) those other namespaces.
Namespaces are used to organize code into logical groups and to prevent name collisions that can occur especially when your code base includes multiple libraries.
The alternative is to write std:: everywhere.
Advantages of namespace In one program, namespace can help define different scopes to provide scope to different identifiers declared within them. By using namespace - the same variable names may be reused in a different program.
Mostly I wonder what the benefits would be (as Raymond Chen says, every feature starts with -100 points). However, I have a counterpoint to offer: Luabind, which does use something that looks like this. See luabind/object.hpp, which essentially says:
namespace luabind {
namespace adl {
class object {
};
}
using adl::object;
}
From the name alone we can infer the motivation: to support argument-dependent lookup. Given what the user knows as a luabind::object
, which is actually a luabind::adl::object
, related functions will be discovered automatically by the compiler from the luabind::adl
namespace. Yet those functions, which the user may not need to know about in a very explicit way, do not "pollute" the main luabind
namespace. So that's nice, I guess.
But you know what's not nice? Forward declaring one of these classes. This fails:
namespace luabind { class object; }
You need to do this instead:
namespace luabind { namespace adl { class object; } }
Thus the abstraction quickly leaks, as the user does need to know about this magic adl
namespace after all.
Simply because nobody learns it. Most programmers are taught Java-style OOP, and it's more common to see C++ code which encapsulates a namespace-style API into a class
.
C++ has argument-dependent function lookup (ADL), which allows it to select a function from an API based on the namespaces of the types of the arguments it's called with. It's a powerful mechanism which allows you to bypass much of the OOP boilerplate yet retain the benefits. But it's not really taught to beginners, for no good particular reason.
For what it's worth, your example is roughly equivalent to this condensed version:
namespace api {
struct array {
friend void print(const array&) { }
};
struct list {
friend void print(const list&) { }
};
}
When you define a function as a friend
within a class, it belongs not to the class, but the enclosing namespace. Moreover, its name is available only within the class, not the enclosing namespace, except when it's called using the class as an argument.
Polluting the global namespace with array_api
and list_api
namespaces is a bad idea. Better to make a hierarchy as in my example.
So, given the above, you could do this:
api::array x;
print( x ); // ADL finds api::print defined inside api::array
Indeed, this is how the iostream-style operator <<
works. You don't need a using
declaration (or directive) to print objects from a library.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With