cos, sin, tan
etc. are to be used
accepting arguments in degrees rather than arguments in
radians. Unfortunately, the function name cos
is already in use, and that
function accepts radians as its arguments, rather than degrees.
Problems like these are usually solved by defining another name, e.g., the
function name cosDegrees
is defined. C++ offers an alternative
solution through namespaces. Namespaces can be considered as
areas or regions in the code in which identifiers may be defined. Identifiers
defined in a namespace normally won't conflict with names already defined
elsewhere (i.e., outside of their namespaces). So, a function cos
(expecting angles in degrees) could be defined in a namespace
Degrees
. When calling cos
from within Degrees
you would call the
cos
function expecting degrees, rather than the standard cos
function
expecting radians.
namespace identifier { // declared or defined entities // (declarative region) }The identifier used when defining a namespace is a standard C++ identifier.
Within the declarative region, introduced in the above code example,
functions, variables, structs, classes and even (nested) namespaces can be
defined or declared. Namespaces cannot be defined within a function
body. However, it is possible to define a namespace using multiple
namespace declarations. Namespaces are `open' meaning that
a namespace CppAnnotations
could be defined in a file file1.cc
and
also in a file file2.cc
. Entities defined in the CppAnnotations
namespace of files file1.cc
and file2.cc
are then united in one
CppAnnotations
namespace region. For example:
// in file1.cc namespace CppAnnotations { double cos(double argInDegrees) { ... } } // in file2.cc namespace CppAnnotations { double sin(double argInDegrees) { ... } }Both
sin
and cos
are now defined in the same
CppAnnotations
namespace.
Namespace entities can be defined outside of their namespaces. This topic is discussed in section 4.1.4.1.
namespace CppAnnotations { double cos(double degrees); double sin(double degrees); }
Entities defined in the anonymous namespace are comparable to C's
static
functions and variables. In C++ the static
keyword can
still be used, but its preferred use is in class
definitions (see
chapter 7). In situations where in C static variables or
functions would have been used the anonymous namespace should be used in
C++.
The anonymous namespace is a closed namespace: it is not possible to add entities to the same anonymous namespace using different source files.
cos()
defined in the CppAnnotations
namespace may be used as follows:
// assume CppAnnotations namespace is declared in the // following header file: #include <cppannotations> int main() { cout << "The cosine of 60 degrees is: " << CppAnnotations::cos(60) << '\n'; }This is a rather cumbersome way to refer to the
cos()
function in the
CppAnnotations
namespace, especially so if the function is frequently
used. In cases like these an abbreviated form can be
used after specifying a using declaration. Following
using CppAnnotations::cos; // note: no function prototype, // just the name of the entity // is required.calling
cos
results in a call of the cos
function defined in the
CppAnnotations
namespace. This implies that the standard cos
function, accepting radians, is not automatically called anymore. To call that
latter cos
function the plain
scope resolution operator should be used:
int main() { using CppAnnotations::cos; ... cout << cos(60) // calls CppAnnotations::cos() << ::cos(1.5) // call the standard cos() function << '\n'; }A
using
declaration can have restricted scope. It can be used inside a
block. The using
declaration prevents the definition of entities having
the same name as the one used in the using
declaration. It is not possible
to specify a using
declaration for a variable value
in some namespace,
and to define (or declare) an identically named object in a block also
containing a using
declaration. Example:
int main() { using CppAnnotations::value; ... cout << value << '\n'; // uses CppAnnotations::value int value; // error: value already declared. }
using
declaration is the
using directive:
using namespace CppAnnotations;Following this directive, all entities defined in the
CppAnnotations
namespace are used as if they were declared by using
declarations.
While the using
directive is a quick way to
import all the names of a namespace (assuming
the namespace has previously been declared or defined), it is at the same time
a somewhat dirty way to do so, as it is less clear what entity is actually
used in a particular block of code.
If, e.g., cos
is defined in the CppAnnotations
namespace,
CppAnnotations::cos
is going to be used when cos
is called. However,
if cos
is not defined in the CppAnnotations
namespace, the
standard cos
function will be used. The using
directive does not
document as clearly as the using
declaration what entity will actually be
used. Therefore use caution when applying the using
directive.
Namespace declarations are context sensitive: when a using namespace
declaration is specified inside a compound statement then the declaration is
valid until the compound statement's closing curly bracket has been
encountered. In the next example a string first
is defined without
explicit specifying std::string
, but once the compound statement has ended
the scope of the using namespace std
declaration has also ended, and so
std::
is required once again when defining second
:
#include <string> int main() { { using namespace std; string first; } std::string second; }A
using namespace
directive cannot be used within the
declaration block of a class- or enumeration-type. E.g., the following example
won't compile:
struct Namespace { using namespace std; // won't compile };
`Koenig lookup' refers to the fact that if a function is called without specifying its namespace, then the namespaces of its argument types are used to determine the function's namespace. If the namespace in which the argument types are defined contains such a function, then that function is used. This procedure is called the `Koenig lookup'.
As an illustration consider the next example. The function
FBB::fun(FBB::Value v)
is defined in the FBB
namespace. It
can be called without explicitly mentioning its namespace:
#include <iostream> namespace FBB { enum Value // defines FBB::Value { FIRST }; void fun(Value x) { std::cout << "fun called for " << x << '\n'; } } int main() { fun(FBB::FIRST); // Koenig lookup: no namespace // for fun() specified } /* generated output: fun called for 0 */The compiler is rather smart when handling namespaces. If
Value
in the
namespace FBB
would have been defined as typedef int Value
then
FBB::Value
would be recognized as int
, thus causing the Koenig lookup
to fail.
As another example, consider the next program. Here two namespaces are
involved, each defining their own fun
function. There is no
ambiguity, since the argument defines the namespace and FBB::fun
is
called:
#include <iostream> namespace FBB { enum Value // defines FBB::Value { FIRST }; void fun(Value x) { std::cout << "FBB::fun() called for " << x << '\n'; } } namespace ES { void fun(FBB::Value x) { std::cout << "ES::fun() called for " << x << '\n'; } } int main() { fun(FBB::FIRST); // No ambiguity: argument determines // the namespace } /* generated output: FBB::fun() called for 0 */
Here is an example in which there is an ambiguity: fun
has two
arguments, one from each namespace. The ambiguity must be resolved by the
programmer:
#include <iostream> namespace ES { enum Value // defines ES::Value { FIRST }; } namespace FBB { enum Value // defines FBB::Value { FIRST }; void fun(Value x, ES::Value y) { std::cout << "FBB::fun() called\n"; } } namespace ES { void fun(FBB::Value x, Value y) { std::cout << "ES::fun() called\n"; } } int main() { // fun(FBB::FIRST, ES::FIRST); ambiguity: resolved by // explicitly mentioning // the namespace ES::fun(FBB::FIRST, ES::FIRST); } /* generated output: ES::fun() called */
An interesting subtlety with namespaces is that definitions in one namespace may break the code defined in another namespace. It shows that namespaces may affect each other and that namespaces may backfire if we're not aware of their peculiarities. Consider the following example:
namespace FBB { struct Value {}; void fun(int x); void gun(Value x); } namespace ES { void fun(int x) { fun(x); } void gun(FBB::Value x) { gun(x); } }Whatever happens, the programmer'd better not use any of the functions defined in the
ES
namespace, since that would result in infinite
recursion. However, that's not the point. The point is that the programmer
won't even be given the opportunity to call ES::fun
since the compilation
fails.
Compilation fails for gun
but not for fun
. But why is that so? Why
is ES::fun
flawlessly compiling while ES::gun
isn't? In ES::fun
fun(x)
is called. As x
's type is not defined in a namespace the Koenig
lookup does not apply and fun
calls itself with infinite recursion.
With ES::gun
the argument is defined in the FBB
namespace. Consequently, the FBB::gun
function is a possible candidate to
be called. But ES::gun
itself also is possible as ES::gun
's prototype
perfectly matches the call gun(x)
.
Now consider the situation where FBB::gun
has not yet been
declared. Then there is of course no ambiguity. The programmer responsible for
the ES
namespace is resting happily. Some time after that the programmer
who's maintaining the FBB
namespace decides it may be nice to add a
function gun(Value x)
to the FBB
namespace. Now suddenly the code in
the namespace ES
breaks because of an addition in a completely other
namespace (FBB
). Namespaces clearly are not completely independent of each
other and we should be aware of subtleties like the above. Later in the
C++ Annotations (chapter 11) we'll return to this issue.
Koenig lookup is only used in the context of namespaces. If a function
is defined outside of a namespace, defining a parameter of a type that's
defined inside a namespace, and that namespace also defines a function with an
identical signature, then the compiler reports an ambiguity when that function
is called. Here is an example, assuming the abovementioned namespace FBB
is also available:
void gun(FBB::Value x); int main(int argc, char **argv) { gun(FBB::Value{}); // ambiguity: FBB::gun and ::gun can both // be called. }
std
namespace is reserved by C++. The standard defines many
entities that are part of the runtime available software (e.g., cout, cin,
cerr
); the templates defined in the Standard Template Library (cf.
chapter 18); and the Generic Algorithms (cf. chapter 19)
are defined in the std
namespace.
Regarding the discussion in the previous section, using
declarations may be used when referring to entities in the std
namespace.
For example, to use the std::cout
stream, the code may declare this object as follows:
#include <iostream> using std::cout;Often, however, the identifiers defined in the
std
namespace can all
be accepted without much thought. Because of that, one frequently encounters a
using
directive, allowing the programmer to omit a namespace prefix when
referring to any of the entities defined in the namespace specified with the
using
directive. Instead of specifying using
declarations the
following using
directive is frequently encountered:
construction like
#include <iostream> using namespace std;Should a
using
directive, rather than using
declarations be used?
As a rule of thumb one might decide to stick to using
declarations, up
to the point where the list becomes impractically long, at which point a
using
directive could be considered.
Two restrictions apply to using
directives and
declarations:
namespace std
. This is not compiler enforced but is imposed upon user
code by the standard;
Using
declarations and directives should not be imposed upon
code written by third parties. In practice this means that using
directives and declarations should be banned from header files and should only
be used in source files (cf. section 7.11.1).
namespace CppAnnotations { int value; namespace Virtual { void *pointer; } }The variable
value
is defined in the CppAnnotations
namespace. Within the CppAnnotations
namespace another namespace
(Virtual
) is nested. Within that latter namespace the variable
pointer
is defined. To refer to these
variable the following options are available:
int main() { CppAnnotations::value = 0; CppAnnotations::Virtual::pointer = 0; }
using namespace CppAnnotations
directive can be provided. Now
value
can be used without any prefix, but pointer
must be used
with the Virtual::
prefix:
using namespace CppAnnotations; int main() { value = 0; Virtual::pointer = 0; }
using namespace
directive for the full namespace chain can be
used. Now value
needs its CppAnnotations
prefix again, but
pointer
doesn't require a prefix anymore:
using namespace CppAnnotations::Virtual; int main() { CppAnnotations::value = 0; pointer = 0; }
using namespace
directives none of the
namespace prefixes are required anymore:
using namespace CppAnnotations; using namespace Virtual; int main() { value = 0; pointer = 0; }
using
declarations:
using CppAnnotations::value; using CppAnnotations::Virtual::pointer; int main() { value = 0; pointer = 0; }
using namespace
directives and using
declarations can also be used. E.g., a using namespace
directive
can be used for the CppAnnotations::Virtual
namespace, and a
using
declaration can be used for the CppAnnotations::value
variable:
using namespace CppAnnotations::Virtual; using CppAnnotations::value; int main() { value = 0; pointer = 0; }
Following a using namespace
directive all entities of that namespace
can be used without any further prefix. If a single using namespace
directive is used to refer to a nested namespace, then all entities of that
nested namespace can be used without any further prefix. However, the entities
defined in the more shallow namespace(s) still need the shallow namespace's
name(s). Only after providing specific using namespace
directives or
using
declarations namespace qualifications can be omitted.
When fully qualified names are preferred but a long name like
CppAnnotations::Virtual::pointeris considered too long, a namespace alias may be used:
namespace CV = CppAnnotations::Virtual;This defines
CV
as an alias for the full name. The
variable pointer
may now be accessed using:
CV::pointer = 0;A namespace alias can also be used in a
using namespace
directive or
using
declaration:
namespace CV = CppAnnotations::Virtual; using namespace CV;
Nested namespace definitions
Starting with the C++17 standard, when nesting namespaces a nested namespace can directly be referred to using scope resolution operators. E.g.,
namespace Outer::Middle::Inner { // entities defined/declared here are defined/declared in the Inner // namespace, which is defined in the Middle namespace, which is // defined in the Outer namespace }
To define an entity outside of its namespace its name must be fully
qualified by prefixing the member by its namespaces. The definition may be
provided at the global level or at intermediate levels in the case of nested
namespaces. This allows us to define an entity belonging to namespace A::B
within the region of namespace A
.
Assume the type int INT8[8]
is defined in the CppAnnotations::Virtual
namespace. Furthermore assume that it is our intent to define a function
squares
, inside the namespace
CppAnnotations::Virtual
returning a
pointer to CppAnnotations::Virtual::INT8
.
Having defined the prerequisites within the CppAnnotations::
Virtual
namespace, our function could be defined as follows (cf. chapter 9
for coverage of the memory allocation operator new[]
):
namespace CppAnnotations { namespace Virtual { void *pointer; typedef int INT8[8]; INT8 *squares() { INT8 *ip = new INT8[1]; for (size_t idx = 0; idx != sizeof(INT8) / sizeof(int); ++idx) (*ip)[idx] = (idx + 1) * (idx + 1); return ip; } } }The function
squares
defines an array of one INT8
vector, and
returns its address after initializing the vector by the squares of the first
eight natural numbers.
Now the function squares
can be defined outside of the
CppAnnotations::
Virtual
namespace:
namespace CppAnnotations { namespace Virtual { void *pointer; typedef int INT8[8]; INT8 *squares(); } } CppAnnotations::Virtual::INT8 *CppAnnotations::Virtual::squares() { INT8 *ip = new INT8[1]; for (size_t idx = 0; idx != sizeof(INT8) / sizeof(int); ++idx) (*ip)[idx] = (idx + 1) * (idx + 1); return ip; }In the above code fragment note the following:
squares
is declared inside of the CppAnnotations::Virtual
namespace.
The definition outside of the namespace region requires us to use
the fully qualified name of the function and of its return type.
Inside the body of the function squares
we are within the
CppAnnotations::
Virtual
namespace, so inside the function fully
qualified names (e.g., for INT8
) are not required any more.
Finally, note that the function could also have been defined in the
CppAnnotations
region. In that case the Virtual
namespace would have
been required when defining squares()
and when specifying its return type,
while the internals of the function would remain the same:
namespace CppAnnotations { namespace Virtual { void *pointer; typedef int INT8[8]; INT8 *squares(); } Virtual::INT8 *Virtual::squares() { INT8 *ip = new INT8[1]; for (size_t idx = 0; idx != sizeof(INT8) / sizeof(int); ++idx) (*ip)[idx] = (idx + 1) * (idx + 1); return ip; } }