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: 8.3.1) and please state chapter and paragraph name or number you're referring to.
All received mail is processed conscientiously, and received suggestions for improvements will usually have been 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 are defined that
normally won't conflict with names already defined elsewhere.
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.9.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 will call 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 will be used in
a particular block of code.
If, e.g., cos is defined in the CppAnnotations namespace,
CppAnnotations::cos will 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 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 arguments are used to determine its namespace. If the namespace in which the arguments are defined contains such a function, then that function is used. This is called the `Koenig lookup'.
This is illustrated in the following 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 fairly 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 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 will doubtlessly result in infinite recursion, but 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. Why is that? 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 10) 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.9.1).
namespace CppAnnotations
{
namespace Virtual
{
void *pointer;
}
}
The variable pointer is defined in the Virtual namespace, that
itself is nested under the CppAnnotations namespace. To refer to this
variable the following options are available:
int main()
{
CppAnnotations::Virtual::pointer = 0;
}
using declaration for CppAnnotations::Virtual can be
provided. Now Virtual can be used without any prefix, but
pointer must be used with the Virtual:: prefix:
using CppAnnotations::Virtual;
int main()
{
Virtual::pointer = 0;
}
using declaration for CppAnnotations::Virtual::pointer
can be used. Now pointer can be used without any prefix:
using CppAnnotations::Virtual::pointer;
int main()
{
pointer = 0;
}
using directive or directives can be used:
using namespace CppAnnotations::Virtual;
int main()
{
pointer = 0;
}
Alternatively, two separate using directives could have been used:
using namespace CppAnnotations;
using namespace Virtual;
int main()
{
pointer = 0;
}
using declarations and using
directives can be used. E.g., a using directive can be used for
the CppAnnotations namespace, and a using declaration can be used for
the Virtual::pointer variable:
using namespace CppAnnotations;
using Virtual::pointer;
int main()
{
pointer = 0;
}
At every using directive all entities of that namespace can be used
without any further prefix. If a namespace is nested, then that namespace can
also be used without any further prefix. However, the entities defined in the
nested namespace still need the nested namespace's name. Only after applying a
using declaration or directive the qualified name of the nested namespace
can be omitted.
When fully qualified names are preferred but a long name like
CppAnnotations::Virtual::pointer
is nevertheless 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 declaration or
directive:
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 is 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 8
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;
}
}