A namespace definition begins with the keyword namespace
followed by the namespace name. Following the namespace name is a sequence of declarations and definitions delimited by curly braces. Any declaration that can appear at global scope can be put into a namespace: classes, variables (with their initializations), functions (with their definitions), templates, and other namespaces:
namespace cplusplus_primer {
class Sales_data { / * ... * /};
Sales_data operator+(const Sales_data&,
const Sales_data&);
class Query { /* ... */ };
class Query_base { /* ... */};
} // like blocks, namespaces do not end with a semicolon
This code defines a namespace named cplusplus_primer
with four members: three classes and an overloaded +
operator.
As with any name, a namespace name must be unique within the scope in which the namespace is defined. Namespaces may be defined at global scope or inside another namespace. They may not be defined inside a function or a class.
As is the case for any scope, each name in a namespace must refer to a unique entity within that namespace. Because different namespaces introduce different scopes, different namespaces may have members with the same name.
Names defined in a namespace may be accessed directly by other members of the namespace, including scopes nested within those members. Code outside the namespace must indicate the namespace in which the name is defined:
cplusplus_primer::Query q =
cplusplus_primer::Query("hello");
If another namespace (say, AddisonWesley
) also provides a Query
class and we want to use that class instead of the one defined in cplusplus_primer
, we can do so by modifying our code as follows:
AddisonWesley::Query q = AddisonWesley::Query("hello");
As we saw in § 16.5 (p. 709), unlike other scopes, a namespace can be defined in several parts. Writing a namespace definition:
namespace nsp {
// declarations
}
either defines a new namespace named nsp
or adds to an existing one. If the name nsp
does not refer to a previously defined namespace, then a new namespace with that name is created. Otherwise, this definition opens an existing namespace and adds declarations to that already existing namespace.
The fact that namespace definitions can be discontiguous lets us compose a namespace from separate interface and implementation files. Thus, a namespace can be organized in the same way that we manage our own class and function definitions:
• Namespace members that define classes, and declarations for the functions and objects that are part of the class interface, can be put into header files. These headers can be included by files that use those namespace members.
• The definitions of namespace members can be put in separate source files.
Organizing our namespaces this way also satisfies the requirement that various entities—non-inline functions, static data members, variables, and so forth—may be defined only once in a program. This requirement applies equally to names defined in a namespace. By separating the interface and implementation, we can ensure that the functions and other names we need are defined only once, but the same declaration will be seen whenever the entity is used.
Namespaces that define multiple, unrelated types should use separate files to represent each type (or each collection of related types) that the namespace defines.
Using this strategy for separating interface and implementation, we might define the cplusplus_primer
library in several separate files. The declarations for Sales_data
and its related functions would be placed in Sales_data.h
, those for the Query
classes of Chapter 15 in Query.h
, and so on. The corresponding implementation files would be in files such as Sales_data.cc
and Query.cc
:
// ---- Sales_data.h----
// #includes should appear before opening the namespace
#include <string>
namespace cplusplus_primer {
class Sales_data { /* ... */};
Sales_data operator+(const Sales_data&,
const Sales_data&);
// declarations for the remaining functions in the Sales_data interface
}
// ---- Sales_data.cc----
// be sure any #includes appear before opening the namespace
#include "Sales_data.h"
namespace cplusplus_primer {
// definitions for Sales_data members and overloaded operators
}
A program using our library would include whichever headers it needed. The names in those headers are defined inside the cplusplus_primer
namespace:
// ---- user.cc----
// names in the Sales_data.h header are in the cplusplus_primer namespace
#include "Sales_data.h"
int main()
{
using cplusplus_primer::Sales_data;
Sales_data trans1, trans2;
// ...
return 0;
}
This program organization gives the developers and the users of our library the needed modularity. Each class is still organized into its own interface and implementation files. A user of one class need not compile names related to the others. We can hide the implementations from our users, while allowing the files Sales_data.cc
and user.cc
to be compiled and linked into one program without causing any compile-time or link-time errors. Developers of the library can work independently on the implementation of each type.
It is worth noting that ordinarily, we do not put a #include
inside the namespace. If we did, we would be attempting to define all the names in that header as members of the enclosing namespace. For example, if our Sales_data.h
file opened the cplusplus_primer
before including the string
header our program would be in error. It would be attempting to define the std
namespace nested inside cplusplus_primer
.
Assuming the appropriate declarations are in scope, code inside a namespace may use the short form for names defined in the same (or in an enclosing) namespace:
#include "Sales_data.h"
namespace cplusplus_primer { // reopen cplusplus_primer
// members defined inside the namespace may use unqualified names
std::istream&
operator>>(std::istream& in, Sales_data& s) { /* ... */}
}
It is also possible to define a namespace member outside its namespace definition. The namespace declaration of the name must be in scope, and the definition must specify the namespace to which the name belongs:
// namespace members defined outside the namespace must use qualified names
cplusplus_primer::Sales_data
cplusplus_primer::operator+(const Sales_data& lhs,
const Sales_data& rhs)
{
Sales_data ret(lhs);
// ...
}
As with class members defined outside a class, once the fully qualified name is seen, we are in the scope of the namespace. Inside the cplusplus_primer
namespace, we can use other namespace member names without qualification. Thus, even though Sales_data
is a member of the cplusplus_primer
namespace, we can use its unqualified name to define the parameters in this function.
Although a namespace member can be defined outside its namespace, such definitions must appear in an enclosing namespace. That is, we can define the Sales_data operator+
inside the cplusplus_primer
namespace or at global scope. We cannot define this operator in an unrelated namespace.
Template specializations must be defined in the same namespace that contains the original template (§ 16.5, p. 709). As with any other namespace name, so long as we have declared the specialization inside the namespace, we can define it outside the namespace:
// we must declare the specialization as a member of std
namespace std {
template <> struct hash<Sales_data>;
}
// having added the declaration for the specialization to std
// we can define the specialization outside the std namespace
template <> struct std::hash<Sales_data>
{
size_t operator()(const Sales_data& s) const
{ return hash<string>()(s.bookNo) ^
hash<unsigned>()(s.units_sold) ^
hash<double>()(s.revenue); }
// other members as before
};
Names defined at global scope (i.e., names declared outside any class, function, or namespace) are defined inside the global namespace. The global namespace is implicitly declared and exists in every program. Each file that defines entities at global scope (implicitly) adds those names to the global namespace.
The scope operator can be used to refer to members of the global namespace. Because the global namespace is implicit, it does not have a name; the notation
::member_name
refers to a member of the global namespace.
A nested namespace is a namespace defined inside another namespace:
namespace cplusplus_primer {
// first nested namespace: defines the Query portion of the library
namespace QueryLib {
class Query { /* ... */ };
Query operator&(const Query&, const Query&);
// ...
}
// second nested namespace: defines the Sales_data portion of the library
namespace Bookstore {
class Quote { /* ... */ };
class Disc_quote : public Quote { /* ... */ };
// ...
}
}
The cplusplus_primer
namespace now contains two nested namespaces: the namespaces named QueryLib
and Bookstore
.
A nested namespace is a nested scope—its scope is nested within the namespace that contains it. Nested namespace names follow the normal rules: Names declared in an inner namespace hide declarations of the same name in an outer namespace. Names defined inside a nested namespace are local to that inner namespace. Code in the outer parts of the enclosing namespace may refer to a name in a nested namespace only through its qualified name: For example, the name of the class declared in the nested namespace QueryLib
is
cplusplus_primer::QueryLib::Query
The new standard introduced a new kind of nested namespace, an inline namespace. Unlike ordinary nested namespaces, names in an inline namespace can be used as if they were direct members of the enclosing namespace. That is, we need not qualify names from an inline namespace by their namespace name. We can access them using only the name of the enclosing namespace.
An inline namespace is defined by preceding the keyword namespace
with the keyword inline
:
inline namespace FifthEd {
// namespace for the code from the Primer Fifth Edition
}
namespace FifthEd { // implicitly inline
class Query_base { /* ... * /};
// other Query-related declarations
}
The keyword must appear on the first definition of the namespace. If the namespace is later reopened, the keyword inline
need not be, but may be, repeated.
Inline namespaces are often used when code changes from one release of an application to the next. For example, we can put all the code from the current edition of the Primer into an inline namespace. Code for previous versions would be in non-inlined namespaces:
namespace FourthEd {
class Item_base { /* ... */};
class Query_base { /* ... */};
// other code from the Fourth Edition
}
The overall cplusplus_primer
namespace would include the definitions of both namespaces. For example, assuming that each namespace was defined in a header with the corresponding name, we’d define cplusplus_primer
as follows:
namespace cplusplus_primer {
#include "FifthEd.h"
#include "FourthEd.h"
}
Because FifthEd
is inline, code that refers to cplusplus_primer::
will get the version from that namespace. If we want the earlier edition code, we can access it as we would any other nested namespace, by using the names of all the enclosing namespaces: for example, cplusplus_primer::FourthEd::Query_base
.
An unnamed namespace is the keyword namespace
followed immediately by a block of declarations delimited by curly braces. Variables defined in an unnamed namespace have static lifetime: They are created before their first use and destroyed when the program ends.
An unnamed namespace may be discontiguous within a given file but does not span files. Each file has its own unnamed namespace. If two files contain unnamed namespaces, those namespaces are unrelated. Both unnamed namespaces can define the same name; those definitions would refer to different entities. If a header defines an unnamed namespace, the names in that namespace define different entities local to each file that includes the header.
Unlike other namespaces, an unnamed namespace is local to a particular file and never spans multiple files.
Names defined in an unnamed namespace are used directly; after all, there is no namespace name with which to qualify them. It is not possible to use the scope operator to refer to members of unnamed namespaces.
Names defined in an unnamed namespace are in the same scope as the scope at which the namespace is defined. If an unnamed namespace is defined at the outermost scope in the file, then names in the unnamed namespace must differ from names defined at global scope:
int i; // global declaration for i
namespace {
int i;
}
// ambiguous: defined globally and in an unnested, unnamed namespace
i = 10;
In all other ways, the members of an unnamed namespace are normal program entities. An unnamed namespace, like any other namespace, may be nested inside another namespace. If the unnamed namespace is nested, then names in it are accessed in the normal way, using the enclosing namespace name(s):
namespace local {
namespace {
int i;
}
}
// ok: i defined in a nested unnamed namespace is distinct from global i
local::i = 42;
Exercise 18.12: Organize the programs you have written to answer the questions in each chapter into their own namespaces. That is, namespace chapter15
would contain code for the Query
programs and chapter10
would contain the TextQuery
code. Using this structure, compile the Query
code examples.
Exercise 18.13: When might you use an unnamed namespace?
Exercise 18.14: Suppose we have the following declaration of the operator*
that is a member of the nested namespace mathLib::MatrixLib
:
namespace mathLib {
namespace MatrixLib {
class matrix { /* ... */ };
matrix operator*
(const matrix &, const matrix &);
// ...
}
}
How would you declare this operator in global scope?