Sometimes one namespace isn’t enough. You create a very broad namespace like Graphics, but then you start creating code for drawing, color management, and matrix arithmetic all of which you’d like to organize as separate groups, yet under the same heading. Nested namespaces enable you to achieve exactly that - a namespace that lives inside another namespace.
The syntax is simple, you start with one namespace and, inside its braces, you declare a second one:
#include <iostream>
namespace Graphics
{
namespace Color
{
void setRed()
{
std::cout << "Red channel set\n";
}
}
}
int main()
{
Graphics::Color::setRed();
return 0;
}
Here we created a top-level namespace Graphics, and inside it, we put another namespace Color. Therefore, the function setRed actually belongs to Color, which in turn belongs to Graphics. If you want to call it from your code in main you need to specify the whole path: Graphics::Color::setRed.
If you omit any part of the name, your code will refuse to compile.
The name setRed is not visible directly or at any higher level of nesting.
You can nest as deeply as you wish. With each extra level the qualified name just gets longer and has more colons added:
#include <iostream>
namespace Company
{
namespace Project
{
namespace Utils
{
int add(int a, int b)
{
return a + b;
}
}
}
}
int main()
{
int sum{ Company::Project::Utils::add(10, 20) };
std::cout << "Sum is " << sum << '\n';
return 0;
}
Here we’ve stacked three namespaces. Company holds Project, which holds Utils. The function add lives within Utils.
To call it we need the full name - Company::Project::Utils::add - passing the arguments 10 and 20 and getting back 30.
Each :: takes you one step down a level in the nesting hierarchy; each step must exist, or the compiler won’t find the name.
You can open a nested namespace again, just like you can with a regular one. You need to open the outer namespace again and again (with its nested member namespaces up to the one you want to reopen) and just add more declarations:
#include <iostream>
namespace Audio
{
namespace Effects
{
void echo()
{
std::cout << "Echo applied\n";
}
}
}
namespace Audio
{
namespace Effects
{
void reverb()
{
std::cout << "Reverb applied\n";
}
}
}
int main()
{
Audio::Effects::echo();
Audio::Effects::reverb();
return 0;
}
The first code block defines the Audio and Effects namespaces and puts the echo function in Audio::Effects. The second code block again starts namespace Audio { namespace Effects { ... } } but adds a new member function named reverb. Now echo and reverb both live inside Audio::Effects. When you call them, you need to spell out the entire path.
If you leave out one of the intermediate names, the compiler cannot find the function:
// this will not compile
Effects::echo(); // error, Effects is not visible outside Audio
Audio::echo(); // error, echo is not a direct member of Audio
You have to fully spell out Audio::Effects::echo() to have the compiler understand where echo is located. Nested namespaces impose a very strict hierarchy where the complete path must be specified every time.
Nesting allows you to group relevant names together without having to clutter the whole namespace with all of your symbols. The outermost namespaces serve as high-level categorisations; inner namespaces refine and specialise these top-level groups. The scope resolution operator (the colons - ::) is merely a way of navigating this hierarchy.
0 comments
No comments yet. Be the first.