Exercises — Namespaces — avoiding name collisions
Before we start, one picture to keep in your head for the whole page — the "prefix box" model of a name.

Every name you write is really a full name = the box labels stacked with ::, then the identifier at the end. Two names collide only when their full names match exactly.
Level 1 — Recognition
Goal: recognise the syntax and what each piece means. No tracing yet.
Recall Solution
:: is the scope-resolution operator. It says "look for the name on the right inside the scope named on the left" — here, find cout inside the std namespace, so the candidate set becomes exactly {std::cout}.
Recall Solution
- (a) = using-declaration — brings in exactly one name,
cout. - (b) = Qualified — the full name is spelled out, always unambiguous.
- (c) = using-directive — dumps all of
stdinto the current scope (the risky one). Mnemonic from the parent: Q-D-D = Qualify, Declare one, Dump all.
Recall Solution
A leading :: with nothing before it means "start lookup at the very top — the global (unnamed) namespace." So ::swap forces the global swap, ignoring any local using that pulled in a different swap.
Level 2 — Application
Goal: predict what a small program prints or whether it compiles.
Recall Solution
Geometry::area(2.0).Statistics::area(3.0, 4.0). Same short namearea, different full names (Geometry::areavsStatistics::area) → no clash, and the argument list also differs so even overload resolution is happy.
Recall Solution
- Unqualified
parseinparse + 1resolves to the global variableint parse = 5, soa = 5 + 1 = 6. JsonLib::parse("{}")is fully qualified, so it calls the library function, returning42, sob = 42. The full names::parse(variable) andJsonLib::parse(function) differ → both legal at once.
Recall Solution
Active is an alias for FastImpl, so Active::sqrt_(16) calls FastImpl::sqrt_(16) = 16/2 = 8, giving r = 8.
Switching the alias to ExactImpl makes it ExactImpl::sqrt_(16) = 16/4 + 1 = 4 + 1 = 5. One line flips every Active:: call — no collisions because only the synonym changed, not any name.
Level 3 — Analysis
Goal: trace name lookup step by step and diagnose errors.
The lookup rule, as a diagram — memorise the order:

Recall Solution
Both using-directives inject their f into the current scope with equal rank. When the compiler does lookup on unqualified f, it finds two equally good candidates {A::f, B::f} → ambiguity error (it refuses to guess).
Fix: qualify → A::f();. This forces the candidate set to exactly {A::f}, one match, done.
Recall Solution
Two levels are visible with equal rank inside g (the global ::level and the using-directive's Tools::level), so unqualified level is ambiguous — it will not compile.
To pick one explicitly:
- global one →
::level(value99), - Tools one →
Tools::level(value1). Leading::= "start at the top"; theTools::prefix pins the other.
Recall Solution
z = 1. A using-declaration (using Tools::level;) acts like a local declaration of that name inside h. A locally declared name hides the global ::level rather than competing at equal rank — the nearest scope wins outright. So unqualified level is Tools::level = 1, unambiguously.
Contrast with L3.2's using-directive, which does not declare locally, so both names stayed at equal rank and clashed.
Level 4 — Synthesis
Goal: design namespace structure to solve a real organisation problem.
Recall Solution
// net.h
#ifndef NET_H // include guard (see Header Files topic)
#define NET_H
namespace Net {
void send(); // full name: Net::send — declaration only
}
#endif// net.cpp
#include "net.h"
void Net::send() { /* real code, defined ONCE */ }// user.cpp
#include "net.h"
void send() { /* user's own */ } // full name ::send — no clash!
Net::send(); // explicitly your library'sWhy it works: the header puts send in Net (full name Net::send) and contains no using namespace, so it adds nothing to the user's unqualified scope. The user's ::send and your Net::send have different full names → both coexist. Also note: the header only declares; the single definition lives in net.cpp, honouring the One Definition Rule (ODR).
Recall Solution
Technique A — alias (recommended, local & explicit):
namespace CPN = Company::Project::Net;
int a = CPN::port; // short, still uniquely CPN == Company::Project::NetTechnique B — targeted using-declaration:
using Company::Project::Net::port;
int a = port; // brings in ONLY 'port'Both keep uniqueness. Avoid using namespace Company::Project::Net; if the file has other port-like names, since a directive risks ambiguity (L3 lessons).
Level 5 — Mastery
Goal: edge cases — linkage, ODR, and unnamed namespaces.

Recall Solution
No — linker error. A namespace is open: it spans files, so App::counter in a.cpp and App::counter in b.cpp are two definitions of one entity → an One Definition Rule (ODR) violation. The linker sees App::counter defined twice.
Correct pattern: declare once in a header with extern, define once in a single .cpp:
// app.h
namespace App { extern int counter; } // declaration (no storage)
// app.cpp
namespace App { int counter = 0; } // the ONE definitionextern says "this name exists somewhere with external linkage — don't allocate it here" (see Linkage — internal vs external).
Recall Solution
No clash. An unnamed namespace gives its members internal linkage — each is visible only within its own translation unit (.cpp). So helper/tick in file1.cpp and in file2.cpp are distinct entities the linker never compares. This is the modern replacement for file-scope static. (See Scope and Storage Duration and Linkage — internal vs external.)
Recall Solution
The using-directive made My::swap visible, so unqualified swap(a,b) risks the buggy one. Force the library's:
std::swap(a, b); // full name pins The Standard Library versionAfter it, a = 7 and b = 3 (values exchanged). Qualifying with std:: shrinks the candidate set to exactly {std::swap}, bypassing My::swap entirely. (See The Standard Library (std).)
Recall Solution
.
Each v is pinned by its prefix to a different full name, so there is no ambiguity even though the identifier v repeats.
80/20 recap
Recall The vital few from these exercises
Prefix box makes full names ::: full name = box labels joined by :: then the identifier; collide only if full names match.
using-declaration vs using-directive ::: declaration hides competitors (nearest wins); directive adds names at equal rank (can ambiguate).
Leading :: means ::: start lookup at the global/top scope.
Two definitions of Ns::x in two files ::: ODR violation — declare once with extern, define once.
Unnamed namespace gives ::: internal linkage — file-local, no cross-file clash, replaces file-scope static.
Force the std version ::: qualify with std::, e.g. std::swap(a,b).
Connections
- 5.2.04 Namespaces — avoiding name collisions (Hinglish)
- Scope and Storage Duration
- One Definition Rule (ODR)
- Header Files and Include Guards
- Classes and Encapsulation
- Linkage — internal vs external
- The Standard Library (std)