03 - namespaces

Namespaces are C++ equivalent of filesystem directories. They group entities under same name prefix, but :: is used instead of /.

The primary purpose of namespaces is grouping related entities and preventing name conflicts. C++ standard library uses namespace std but there are some inner namespaces too, e.g. std::chrono.

Syntax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
namespace foo { void f1(); }

// namespaces can be opened multiple times, potentially in different files
namespace foo { void f2(); }

// namespaces can be nested and entities can appear at any level
namespace bar {
	void f3();

	namespace foo { // bar::foo is not the same as foo
		void f4();

		namespace baz {
			void f5();
		}

		void f6();
	}
}

// definitions of entities can appear in another namespace definition...
namespace foo { void f1() {} }
// ...or use qualified name
void foo::f2() {}

// inside a namespace, enclosing namespace names can be skipped
// this applies to any code that uses entities from enclosed namespace
namespace bar {
	void f3() {}
	void foo::f4() {}      // no need to write bar::foo::f4
	void foo::baz::f5() {} // no need to write bar::foo::baz::f5
}

// out-of-namespace definitions and redeclarations can not appear
// in a namespace that does not enclose original declaration
namespace xyz {
	// error: xyz::bar::foo::f6 does not exist
	// this syntax (qualified-id) can not be used to declare new entities
	// void bar::foo::f6() {}
}

// :: can be used before the name to refer to shadowed entity
void f();
namespace abc {
	void f() // hides (shadows) global f
	{
		::f(); // ok: calls ::f (not a recursion)
	}
}

// it's possible to create namespace aliases
namespace abc {
	namespace bfb = ::bar::foo::baz;
}

void f7()
{
	abc::bfb::f5(); // ok: calls bar::foo::baz::f5
}

using

The keyword has 4 possible meanings, depending on the context:

  • type aliases

  • using-declaration, inside classes (changes overloading rules in derived types)

  • using-declaration, outside classes (shortens names)

  • using-directive (shortens names)

This article explains the last 2.

Using-declaration

Introduces names from other namespaces to current namespace or block scope (if used inside a function).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void f();

namespace abc
{
	void g1();
	void g2();
}

namespace xyz
{
	using ::f;
	using abc::g1;
}

void h()
{
	xyz::f();  // calls ::f
	xyz::g1(); // calls abc::g1

	using abc::g2;
	g2(); // calls abc::g2
}

The declaration introduces all entities with specified name. In particular, the name can refer to a template or to a set of function overloads. The declaration applies only to entities that have already been declared:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
namespace abc
{
	void f(int);
}
using abc::f; // ::f is now a synonym for abc::f(int)

namespace abc
{
	void f(char); // does not change what ::f means
}

void foo()
{
	f('a'); // calls f(int), even though f(char) exists.
}

void bar()
{
	using abc::f; // introduces both overloads
	f('a');       // calls f(char)
}

using namespace does not have this behavior - for it the order of declarations is irrelevant (all names will be affected, not only ones defined before).

If using-declaration introduces names from different scopes, ambiguity errors appear only under specific usages. If using-declaration attempts to introduce something that is already in the current scope, it's an error.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
namespace abc
{
	void f(int);
	void f(double);

	void g(int);
}

namespace xyz
{
	void f(int);
	void f(double);
	void f(char);
}

void g();
// using abc::g; // error: g already in this scope

// no error even though some overloads are identical
using abc::f;
using xyz::f;

// void f(int); // error: conflicts with abc::f(int) and xyz::f(int)

void h()
{
	f('h'); // calls xyz::f(char)
	f(1.0); // error: ambiguity between abc::f(double) and xyz::f(double)
}

Using-directive

Similar to using-declaration, but introduces all names from specified namespace to the current scope.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
namespace abc
{
	int i = 1;
	void f(char);
}

namespace foo
{
	int i = 2;
	int j = 3;

	namespace bar
	{
		namespace baz
		{
			// names from abc injected into global namespace
			// (including any names later declared in abc)
			using namespace abc;

			int j = 4;
			int k = 5;
			int a = i; // ok: foo::i hides abc::i
		}

		// names from baz injected into bar
		// names from abc injected into global namespace (using namespace is transitive)
		using namespace baz;

		int l = k; // ok, uses baz::k
		int k = 6; // ok, no name conflict
		int m = k; // error: bar::k or baz::k?
		int n = i; // ok: foo::i hides abc::i
		int o = j; // ok: baz::j hides foo::j
	}
}

using namespace abc;

namespace xyz
{
	int e = 7;
	void f(int);
}

namespace abc
{
	int d = 8;
	using namespace xyz;
	void f(int);
}

int d = 9;

void func()
{
	++d;      // error: ::d or abc::d?
	++::d;    // ok
	++abc::d; // ok
	++e;      // ok (using namespace is transitive)

	f(1);     // error: xyz::f(int) or abc::f(int)?
	f('a');   // ok: abc::f(char)
}

using namespace std;

Shortly speaking, one of the most overused statements in C++. There is so much to say about it that I wrote a separate article about it. TOLINK

using enum

Since C++20 it's also possile to bring enumerator names into enclosing scope.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
enum class fruit { apple, orange };
enum class color { green, orange, red };

struct boo
{
	using enum fruit;
};

void f()
{
	// ok: auto = fruit
	auto x = boo::orange;
	// also ok, but I wouldn't write such code
	// I guess this syntax is allowed to make writing templates easier
	boo b;
	auto y = b.orange;
}

void g()
{
	using enum fruit; // ok: you can now use apple and orange
	using enum color; // error: fruit::orange and color::orange conflict
}

It's also possible to do it for single enumerators by writing code like using color::red.

Anonymous namespaces

Formally unnamed-namespace-definition but the "anonymous" term is very popular in the community. Works as if the namespace has some unique name and is immediately followed by using namespace. Can also be mentally understood as "not actually enclosing entities in any namespace".

Everything defined inside anonymous namespaces has internal linkage. This includes named namespaces inside. The purpose of this feature is to further reduce name conflicts, but specifically across TUs. You should put there all things that are not being used outside of current source file and do not need to be visible to other TUs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// header
std::string important_complex_function(int x, int y, double n)

// source
namespace {
	// many helper functions that are used only in this file
	// all will have *internal linkage*
	// the same names can be reused in other TUs
}

std::string important_complex_function(int x, int y, double n)
{
	// uses many helper functions...
}

You might notice that the same functionality was already presented with static - anonymous namespaces should be preferred. Why? See these:

Inline namespaces

Inline namespaces work similarly to anonymous namespaces - names are available in enclosing namespace, as if there was a using namespace directive after it's definition. There are no changes in linkage though.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace foo {
	inline namespace bar {
		void f();

		inline namespace baz {
			void g();
		}
	}
}

void func()
{
	// namespace names can be specified explicitly
	foo::bar::f();
	foo::bar::baz::g();

	// namespace names can have inline namespaces ommitted
	foo::f();
	foo::g();
}

This feature has 2 purposes.

Finely-grained usings

Names are available in enclosing scopes, without having to specify their inline namespace name. But using directives can be more selective. Below is an example with standard library user-defined literals.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// synopsis from standard library implementation
namespace std {

	inline namespace literals {
		// note: there are more literal overloads than listed here

		inline namespace string_literals {
			constexpr string operator""s(const char* str, size_t len); // constexpr since C++20
		}

		inline namespace chrono_literals {
			constexpr chrono::seconds operator""s(unsigned long long secs);
		}
	}

	namespace chrono {
		using namespace literals::chrono_literals;
	}

}

// example uses
{
	using namespace std; // makes both suffixes visible
	auto str = "abc"s; // auto = std::string
	auto min = 60s;    // auto = std::chrono::seconds
}

{
	using namespace std::literals; // makes both suffixes visible
	auto str = "abc"s;
	auto min = 60s;
}

{
	using std::operator""s; // makes both suffixes visible
	auto str = "abc"s;
	auto min = 60s;
}

{
	using namespace std::string_literals; // string literal suffixes only
	auto str = "abc"s;
}

{
	using namespace std::chrono_literals; // chrono literal suffixes only
	auto min = 60s;
}

{
	using namespace std::chrono; // all std::chrono names, including suffixes
	auto min = 60s;
	auto sec = seconds(1); // auto = std::chrono::seconds
}

Versioning support

Users of a library can refer to specific names or use a default one if automatic behavior updates are desired.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// before update
namespace lib {

	inline namespace v1 {
		void func();
	}

}

// after update
namespace lib {

	namespace v1 {
		void func();
	}

	inline namespace v2 {
		void func();
	}

}

void user_function()
{
	lib::v1::func(); // always first version

	// before update: v1::func
	// after update: v2::func
	lib::func();
}

Apart from being able to select a specific version or use a default, there is one additional important functionality: inline namespaces affect name mangling. What are benefits of this? Suppose a such situation:

  • the programmer compiles library version 1

  • the programmer writes some code that uses the library and compiles it

  • the programmer updates the library and compiles version 2

  • library-using-code is not recompiled and only the compiled library object (e.g. .so or .dll file) is replaced

This can result in undefined behavior due to ODR violations. The library-using-code was compiled with version 1 definitions, but actually linked with version 2. The executable can crash because there can be mismatches between expected and actual size/alignment of structures and many other machine-instruction-level details:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace gis {

	struct geo_zone {
		// [...]
		// additional and/or reordered members in newer version
	};

}

void user_func()
{
	// compiled user code with old version (function-local object):
	// allocates sizeof(gis::geo_zone) bytes on the stack with alignof(gis::geo_zone) alignment
	// compiled library code with new version (library function):
	// writes sizeof(gis::geo_zone) bytes, *this size may differ from size in user code*
	// result: possible stack memory corruption, overwrite of other data on the stack
	gis::geo_zone gz = gis::some_func();
	// compiled user code with old version (member of a type):
	// passes to the function memory address of gz, adjusted by offsetof(gis::geo_zone, time_zone)
	// compiled library code with new version (library function):
	// expects the struct member at a different offset, may break under some optimizations
	gis::other_func(gz.time_zone);
}

Such situation is known as ABI mismatch or ABI breakage. ABI stands for application binary interface. It's different from API (application programming interface) - API pertains to compatibility at the source code level, ABI pertains to compatibility at binary (compiled code) level.

If inline namespaces are used (and changed every time an ABI-breaking change is introduced) such problem can be detected at linking step because compiled entities will have different symbol names - inline namespaces will be present in mangled names.

Using inline namespaces in such case is superior to preprocessor-based solutions because inline namespaces allow providing different definitions for different versions in the same build. If there are disjoint parts of code that use different versions, there are no problems - since these parts don't interact they have no conflicts. As if they used different entities.

As of C++20, the standard library officially does not use inline namespaces for this functionality, but some implementations use it internally - Clang's libc++ uses inline namespace __1. This will help detect ODR violations if compiled code is mixed across versions with different implementations.

Syntax sugar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// C++17 - multiple usings in one statement
using ::f; using abc::g; using xyz::h;
using ::f, abc::g, xyz::h;

// C++17 - defining nested namespaces with one keyword and one {}
namespace na { namespace nb { namespace nc { /* ... */ }}}
namespace na::nb::nc { /* ... */ } // no prior appearance of na and na::nb is required

// C++20 - additionally supports inline
namespace nd::ne { inline namespace nf { /* ... */ }}
namespace nd::ne::inline nf { /* ... */ }

namespace ng { inline namespace nh { namespace ni { /* ... */ }}}
namespace ng::inline nh::ni { /* ... */ }

Recommendation

  • Size of a namespace: no consensus in the community. Some libraries put almost everything in a first-level namespace (like 1000+ names) (std is a very good example), others do many layers with <100 names per namespace. Core Guidelines: as of writing this, namespace size is under to-do section.

  • Avoid name conflicts. You won't need to memorize what happens when ambiguities appear. And I haven't even listed all possible cases.

  • Prefer function-local usings to namespace-level usings.

  • Prefer usings for specific names like using std::cout; instead of whole-namespace usings like using namespace std;.

  • If a conflict would arise, create name or namespace aliases instead to shorten names only (no scope changes) - e.g. namespace bc = boost::container; allows short bc::vector which does not conflict with std::vector.

  • Avoid using namespace in headers. It can hijack code that (potentially transitively) accidentally includes a header with this directive.

Similar recommendations are present in Core Guidelines. Like many other mechanisms in the language, it can be very useful but if abused, it can lead to non-trivial errors and complex situations (especially name shadowing).