Don't hesitate to send in feedback: send an e-mail if you like the C++ Annotations; if you think that important material was omitted; if you find errors or typos in the text or the code examples; or if you just feel like e-mailing. Send your e-mail to Frank B. Brokken.Please state the document version you're referring to, as found in the title (in this document: 10.3.0) and please state chapter and paragraph name or number you're referring to.
All received mail is processed conscientiously, and received suggestions for improvements are usually processed by the time a new version of the Annotations is released. Except for the incidental case I will normally not acknowledge the receipt of suggestions for improvements. Please don't interpret this as me not appreciating your efforts.
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.
Now that the ANSI/ISO standard has been implemented to a large degree in
recent compilers, the use of namespaces is more strictly enforced than in
previous versions of compilers. This affects the setup of
class
header files. At this point in the Annotations this cannot be
discussed in detail, but in section 7.12.1 the construction of
header files using entities from namespaces is discussed.
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.
`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 ES::fun
functions since it results 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.
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.12.1).
std
namespace; this
section can be skipped without loss of continuity.
Before using the namespace std::placeholders
the <functional>
header
file must be included.
Further down the C++ Annotations we will encounter function objects (section
11.10), which are `objects' that can be used as functions. Such function
objects (also called functors) are extensively used in the Standard
Template Library (STL, chapter 18). The STL offers a function
(bind
, see section 18.1.4.1), returning a function adaptor in which a
function is called which may or may not already have received its
arguments. If not, then placeholders for arguments must be used,
for which actual arguments must be specified once the functor that is returned
by bind
is called.
Such placeholders have predefined names: _1, _2, _3,
etc. These
placeholders are defined in the std::placeholders
namespace. Several
illustrations of the use of these placeholders are found in section 18.1.4.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() { 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;
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; } }