Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
53
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

}

Section 44.6: Unnamed/anonymous namespaces

An unnamed namespace can be used to ensure names have internal linkage (can only be referred to by the current translation unit). Such a namespace is defined in the same way as any other namespace, but without the name:

namespace {

int foo = 42;

}

foo is only visible in the translation unit in which it appears.

It is recommended to never use unnamed namespaces in header files as this gives a version of the content for every translation unit it is included in. This is especially important if you define non-const globals.

//foo.h namespace {

std::string globalString;

}

//1.cpp

#include "foo.h" //< Generates unnamed_namespace{1.cpp}::globalString ...

globalString = "Initialize";

// 2.cpp

#include "foo.h" //< Generates unnamed_namespace{2.cpp}::globalString ...

std::cout << globalString; //< Will always print the empty string

Section 44.7: Compact nested namespaces

Version ≥ C++17

namespace a { namespace b {

template<class T>

struct qualifies : std::false_type {};

}

}

namespace other { struct bob {};

}

namespace a::b { template<>

struct qualifies<::other::bob> : std::true_type {};

}

You can enter both the a and b namespaces in one step with namespace a::b starting in C++17.

Section 44.8: Namespace alias

A namespace can be given an alias (i.e., another name for the same namespace) using the namespace identifier = syntax. Members of the aliased namespace can be accessed by qualifying them with the name of the alias. In the

GoalKicker.com – C++ Notes for Professionals

241

following example, the nested namespace AReallyLongName::AnotherReallyLongName is inconvenient to type, so the function qux locally declares an alias N. Members of that namespace can then be accessed simply using N::.

namespace AReallyLongName { namespace AnotherReallyLongName {

int foo(); int bar();

void baz(int x, int y);

}

}

void qux() {

namespace N = AReallyLongName::AnotherReallyLongName; N::baz(N::foo(), N::bar());

}

Section 44.9: Inline namespace

Version ≥ C++11

inline namespace includes the content of the inlined namespace in the enclosing namespace, so

namespace Outer

{

inline namespace Inner

{

void foo();

}

}

is mostly equivalent to

namespace Outer

{

namespace Inner

{

void foo();

}

using Inner::foo;

}

but element from Outer::Inner:: and those associated into Outer:: are identical.

So following is equivalent

Outer::foo();

Outer::Inner::foo();

The alternative using namespace Inner; would not be equivalent for some tricky parts as template specialization:

For

#include <outer.h> // See below

class MyCustomType; namespace Outer

{

GoalKicker.com – C++ Notes for Professionals

242

template <>

void foo<MyCustomType>() { std::cout << "Specialization"; }

}

The inline namespace allows the specialization of Outer::foo

//outer.h

//include guard omitted for simplification

namespace Outer

{

inline namespace Inner

{

template <typename T>

void foo() { std::cout << "Generic"; }

}

}

Whereas the using namespace doesn't allow the specialization of Outer::foo

//outer.h

//include guard omitted for simplification

namespace Outer

{

namespace Inner

{

template <typename T>

void foo() { std::cout << "Generic"; }

}

using namespace Inner;

//Specialization of `Outer::foo` is not possible

//it should be `Outer::Inner::foo`.

}

Inline namespace is a way to allow several version to cohabit and defaulting to the inline one

namespace MyNamespace

{

// Inline the last version inline namespace Version2

{

void foo(); // New version void bar();

}

namespace Version1 // The old one

{

void foo();

}

}

And with usage

MyNamespace::Version1::foo(); // old version MyNamespace::Version2::foo(); // new version

MyNamespace::foo(); // default version : MyNamespace::Version1::foo();

GoalKicker.com – C++ Notes for Professionals

243

Section 44.10: Aliasing a long namespace

This is usually used for renaming or shortening long namespace references such referring to components of a library.

namespace boost

{

namespace multiprecision

{

class Number ...

}

}

namespace Name1 = boost::multiprecision;

//Both Type declarations are equivalent

boost::multiprecision::Number X

//

Writing the full namespace path, longer

Name1::Number Y

//

using the name alias, shorter

Section 44.11: Alias Declaration scope

Alias Declaration are a ected by preceding using statements

namespace boost

{

namespace multiprecision

{

class Number ...

}

}

using namespace boost;

// Both Namespace are equivalent namespace Name1 = boost::multiprecision; namespace Name2 = multiprecision;

However, it is easier to get confused over which namespace you are aliasing when you have something like this:

namespace boost

{

namespace multiprecision

{

class Number ...

}

}

namespace numeric

{

namespace multiprecision

{

class Number ...

}

}

using namespace numeric; using namespace boost;

GoalKicker.com – C++ Notes for Professionals

244

//Not recommended as

//its not explicitly clear whether Name1 refers to

//numeric::multiprecision or boost::multiprecision namespace Name1 = multiprecision;

//For clarity, its recommended to use absolute paths

//instead

namespace Name2 = numeric::multiprecision; namespace Name3 = boost::multiprecision;

GoalKicker.com – C++ Notes for Professionals

245