It’s difficult to imagine even a simple program which doesn’t use something from the std
namespace, so most C++ programmers are introduced to namespaces early on. Namespaces use the same double-colon syntax as static
members of struct
s and class
es, so sometimes it’s not clear to user code which is which. Consider the following code fragment:
#include <cmath>
//...
namespace Math {
struct Constants {
constexpr static auto PI = 2.0 * asin(1.0);
}; // semi-colon is mandatory
}
The fully qualified name of PI
is, of course, Math::Constants::PI
. It is important to note that namespaces are open, that is they can be added to by multiple code fragments (including from different source files). In contrast, the struct
shown here is closed, nothing can be added after the closing curly brace. Here is a possible subsequent addition to namespace Math
:
namespace Math {
struct Functions {
constexpr static double asin(double n) { return ::asin(n); }
};
}
Notice that the prefix ::
within the function body selects the global asin
, thus preventing infinite recursion. Also notice that the same technique, opening a previously defined namespace, could be used to add to the std
namespace; however, according to the Standard doing so leads to undefined behaviour (with a few exceptions).
So, we’re all good with nesting struct
s with static
members inside namespaces. What you may not know is that it is possible to rename a namespace (actually, to make a copy) with a using
directive, for example:
namespace MyNamespace {
using namespace std;
}
This copies all of the contents of the std
namespace, and puts them in the new namespace MyNamespace
, so you would now use MyNamespace::cout
, for example. (This is not possible with struct
s.) More usefully perhaps, it is possible to specify individual entities from std
to put into the namespace with using
statements, as shown in this example program:
#include <iostream>
#include <string_view>
#include <vector>
namespace ext {
using std::cout;
using std::ostream;
using std::vector;
using std::string_view;
}
using namespace std::string_view_literals;
namespace ext {
template <typename T>
ostream& operator<< (ostream& os, vector<T> vec) {
if (vec.empty()) {
return os << "{}"sv;
}
auto sep = ""sv;
os << "{ "sv;
for (const auto &elem : vec) {
os << sep << elem;
sep = ", "sv;
}
os << " }"sv;
return os;
}
}
int main() {
using namespace ext;
vector<int> primes{ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
cout << primes << '\n';
vector<string_view> odd{ "one"sv, "three"sv, "five"sv, "seven"sv, "nine"sv };
cout << odd << '\n';
}
Here we have created a new namespace called ext
at lines 7-12 and added four entities (one object and three types) from std
. The name ext
is commonly used to indicate “extending the Standard Library”. Then line 14 proves you really can mix and match, by enabling string view literal suffixes globally (this means "a string view"sv
is a string view object, not a const char *
).
Lines 18-30 overload the stream extraction operator <<
for ext::vector
(with any element type, you may find this code useful in your own projects) and has to be a generic function qualified with the template
keyword. The parameter list and return type do not have to be fully qualified names, as the whole definition has been wrapped in a second namespace ext
scope (beginning and ending on lines 16 and 31).
The main()
function defined in lines 33-39 should present no surprises. Line 34 is a using
directive that makes all of the contents of ext
(but not std
) available to use locally within the function, without needing to qualify with the namespace name. This includes the overloaded stream extraction operator <<
for ext::vector
, which would otherwise not be visible.
You’re all set to experiment with namespaces on your own now; as an exercise you could follow the steps needed to use endl
instead of '\n'
twice, within main()
. Also, you could try to adapt the code having removed the second namespace scope (qualifying names as needed), and generalize the operator<<
to support any container.
Resources: Download or browse the source code