Occasionally, you may require a name that belongs strictly within a single file and must never be made accessible to any other files. A global function or variable is visible everywhere; a named namespace is accessible from outside the file as long as the other file constructs the proper qualified name. An unnamed namespace simply makes a name private to a particular translation unit.
This kind of namespace is declared with no name specified between the keyword and opening curly brace; thus:
#include <iostream>
namespace
{
void helper()
{
std::cout << "Helper called\n";
}
}
int main()
{
helper();
return 0;
}
The section starting with the bare keyword namespace is an unnamed namespace, and anything declared inside (in this case, a function called helper) belongs entirely to that unnamed section. It cannot be reached with a qualified name since, due to the lack of an explicit name, it is impossible to write such a qualification. Within that same file, however, the names do exist without any qualification, and so the call to helper() in main will find the proper function and make the printout desired.
The primary benefit of unnamed namespaces is that their contents have internal linkage. This means that they are not exposed for linkage from other translation units, so two separate files may have identical function names inside their unnamed namespaces, each of them a separate and independently compiled entity.
// file1.cpp
#include <iostream>
namespace
{
void log()
{
std::cout << "Log from file1\n";
}
}
void run1()
{
log();
}
// file2.cpp
#include <iostream>
namespace
{
void log()
{
std::cout << "Log from file2\n";
}
}
void run2()
{
log();
}
// main.cpp
void run1();
void run2();
int main()
{
run1();
run2();
return 0;
}
In this scenario, there are two source files; in each, there is a function called log, which has internal linkage by virtue of belonging to the unnamed namespace. When main is called, the program will run the functions being called, run1 and run2. Since the two log functions belong to separate translation units and have internal linkage, two different functions named log can exist without producing a linkage error.
The same logic as above does, of course, apply to variables. One need not fear that any names declared here, whether data values or the functions meant to manipulate them, shall be available for linkage from any file other than the current one, even if another translation unit attempts to declare them with extern:
#include <iostream>
namespace
{
int counter{ 0 };
void bump()
{
++counter;
}
}
int main()
{
bump();
bump();
std::cout << "Counter is " << counter << '\n';
return 0;
}
This counter variable and bump function exist only in the unnamed namespace of this translation unit. main will be able to utilize bump and access the value held by counter since those names exist within the local translation unit. Every other translation unit, in attempting to link to these items, cannot do so since those names have internal linkage and are unique to the file that contains them.
Additional members may also be declared in the unnamed namespace at a separate point in the source file in exactly the same manner as any named namespace:
#include <iostream>
namespace
{
void first()
{
std::cout << "First\n";
}
}
namespace
{
void second()
{
std::cout << "Second\n";
}
}
int main()
{
first();
second();
return 0;
}
Here, the second block is still being appended to the first, in terms of adding more elements to the unnamed namespace of this particular translation unit. The second function now added, called second, can now be called just as easily as first, and still from no translation unit other than this one.
Unnamed namespaces present themselves as a means by which to contain implementation details and not reveal any names that belong to them to the rest of the program, and yet still possess names that are extremely easy to type from within that contained translation unit.
0 comments
No comments yet. Be the first.