Long nested names are correct, but they are also tiring to type and tiring to read. When the call looks like Company::Graphics::Rendering::Shaders::load(), then the much more interesting part of the line is lost under a heap of prefixes. A namespace alias gives the long path a short, local name so that everything else remains readable.
The alias is formed by putting the keyword namespace, the new short name, an equals symbol, and the original path:
#include <iostream>
namespace Company
{
namespace Graphics
{
namespace Rendering
{
void draw()
{
std::cout << "Drawing frame\n";
}
}
}
}
int main()
{
namespace Render = Company::Graphics::Rendering;
Render::draw();
return 0;
}
The line namespace Render = Company::Graphics::Rendering; is not creating a new namespace. It simply creates an alias or a synonym named Render for exactly the same namespace as Company::Graphics::Rendering. After the alias exists, the reference to Render::draw() is just the same as writing out the full original path.
The function draw is located, called, and the message is written out.
The alias only exists inside main; outside the function, the short Render name does not exist.
An alias can also appear at different levels of scope. When it appears at namespace scope, it is visible from that point onward within that scope. When it appears within a function, it disappears at the end of that function:
#include <iostream>
namespace Network
{
namespace Protocol
{
namespace Http
{
void send(const char* message)
{
std::cout << "Sending: " << message << '\n';
}
}
}
}
namespace Http = Network::Protocol::Http;
int main()
{
Http::send("Hello");
return 0;
}
Here, the alias Http is declared at namespace scope, and so subsequent declarations in that scope can use Http::send. In main, the call Http::send("Hello") refers to the inner function and outputs the message. The short name remains effective for the rest of that namespace scope.
Aliases are most handy when the same long path occurs many times. Rather than having to type it out on every line, it can be written once as the alias and referred to as:
#include <iostream>
namespace Audio
{
namespace Effects
{
namespace Reverb
{
void apply(int amount)
{
std::cout << "Reverb amount " << amount << '\n';
}
void reset()
{
std::cout << "Reverb reset\n";
}
}
}
}
int main()
{
namespace Rev = Audio::Effects::Reverb;
Rev::apply(40);
Rev::apply(70);
Rev::reset();
return 0;
}
Using namespace Rev = Audio::Effects::Reverb; we just have to write Rev:: before each call from now on. The three calls are now: Rev::apply(40), Rev::apply(70), and Rev::reset(). They actually call the functions they represent within the original nested namespace. Without the alias, the same calls would require the full Audio::Effects::Reverb:: prefix.
An alias is merely a new name for an existing namespace. It doesn't hide the original path; it is available at the same time:
#include <iostream>
namespace Data
{
namespace Store
{
void save()
{
std::cout << "Data saved\n";
}
}
}
int main()
{
namespace DS = Data::Store;
DS::save();
Data::Store::save();
return 0;
}
Both calls go to the same function save. The alias is just an abbreviated spelling; the original nested name still functions correctly.
Since an alias is a synonym, you cannot get around this by starting a new namespace block using the alias name. It is not a new namespace and will always point to whatever path you assigned on the right-hand side.
Namespace aliases are therefore useful for one reason and one reason only: they allow you to retain the advantages of grouping symbols too deeply nested, while giving you short, readable names in the actual code.
0 comments
No comments yet. Be the first.