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::pointer
is 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;
}
}