?? tour-stdcxx.html
字號:
<html>
<head>
<title>
A Tour of NTL: Traditional and ISO Modes </title>
</head>
<body bgcolor="#fff9e6">
<center>
<a href="tour-modules.html"><img src="arrow1.gif" alt="[Previous]" align=bottom></a>
<a href="tour.html"><img src="arrow2.gif" alt="[Up]" align=bottom></a>
<a href="tour-unix.html"> <img src="arrow3.gif" alt="[Next]" align=bottom></a>
</center>
<h1>
<p align=center>
A Tour of NTL: Traditional and ISO Modes
</p>
</h1>
<p> <hr> <p>
<p>
As of version 4.1,
NTL can be compiled and used in one of two modes: Traditional or ISO.
<i>As of NTL version 5.4, ISO mode is the default.</i>
<p>
To revert to traditional mode, you can pass <tt>NTL_STD_CXX=off</tt>
as an argument to the configuration script
when <a href="tour-unix.html">installing NTL on a Unix or Unix-like system</a>,
which will unset the flag <tt>NTL_STD_CXX</tt> in the <tt>config.h</tt>
file.
Alternatively (and especially on non-Unix systems),
you can unset this flag by hand by editing
the the <tt>config.h</tt> file.
<p>
<p>
In Traditional mode, the NTL header files include the traditional
<tt>C++</tt> header files <tt><stdlib.h></tt>,
<tt><math.h></tt>, and <tt><iostream.h></tt>.
These files declare a number of names (functions, types, etc.)
in the <i>global namespace</i>.
Additionally, the NTL header files declare a number of names,
also in the global namespace.
<p>
In ISO mode, three things change:
<ol>
<li>
<b>NTL namespace:</b>
The NTL header files wrap all NTL names in a namespace, called <tt>NTL</tt>.
<p>
<li>
<b>New header files:</b>
The NTL header files include the new <tt>C++</tt>
header files <tt><cstdlib></tt>,
<tt><cmath></tt>, and <tt><iostream></tt>.
These new header files are essentially the same as the traditional ones,
except that all the the names are declared in a namespace called
<tt>std</tt>.
<p>
<li>
<b>Nothrow new:</b>
The NTL implementation files use the <tt>nothrow</tt> version of <tt>new</tt>.
</ol>
<p>
If your complier is not up to date, but you want some of the benefits
of Standard <tt>C++</tt>, you can set the <i>partial standard</i>
flags to get any subset of the above three changes:
<p>
<ol>
<li>
<tt>NTL_PSTD_NNS</tt>: NTL namespace
<li>
<tt>NTL_PSTD_NHF</tt>: New header files
<li>
<tt>NTL_PSTD_NTN</tt>: Nothrow new
</ol>
You can set these flags either by using the configuration script
(only on Unix-like systems), or by editing the <tt>config.h</tt> file.
For example, to just wrap NTL in a namepsace, just pass
<tt>NTL_PSTD_NNS=on</tt>
as an argument to the configuration script
when installing NTL.
However, make sure you also turn off the <tt>NTL_STD_CXX</tt> flag;
otherwise, these have no effect.
<p>
Especially when combining NTL with other libraries, the
<tt>NTL_PSTD_NNS</tt> flag may be particularly useful
in avoiding name clashes, even if your compiler has just a
rudimentary implementation of namespaces.
<p>
NTL will remain usable in Traditional mode indefinitely,
assuming compilers maintain reasonable backward compatibilty with
pre-standard <tt>C++</tt> conventions for header files;
however, if you want to <i>program for the future</i>, it is recommended
to use ISO mode.
The partial ISO modes are not highly recommended;
they are mainly intended as a stop-gap measure
while we wait for decent standard-conforming <tt>C++</tt>
compilers to become available.
<p>
<h3>
A crash course on namespaces
</h3>
<p>
As already mentioned, the main difference between Traditional and ISO
mode is that in ISO mode, all names are wrapped in namespaces.
Namespaces are a feature that was introduced in the new <tt>C++</tt> standard.
One can declare names (functions, types, etc.) inside a namespace.
By default,
such names are not visible outside the namespace without explicit
qualification.
<p>
The main advantage of namespaces is that it solves the <i>namespace pollution
problem</i>:
if two libraries define the same name in two inconsistent ways,
it is very difficult, if not impossible,
to combine these two libraries in the same
program.
<p>
The traditional way of avoiding such problems in languages like
<tt>C</tt> is for a library designer to attach a prefix specific
to that library to all names.
This works, but makes for ugly code.
The function overloading mechanism in <tt>C++</tt> eases the problem a bit,
but is still not a complete solution.
<p>
The new
namespace feature in <tt>C++</tt>
provides a reasonably complete and elegant solution to the namespace
pollution problem.
It is one of the nicest and most important recent additions to the <tt>C++</tt>
language.
<p>
Here is a simple example to illustrate namespaces.
<p>
<pre>
namespace N {
void f(int);
void g(int);
int x;
}
int x;
void h()
{
x = 1; // the global x
N::x = 0; // the x in namespace N
N::f(0); // the f in namespace N
g(1); // error -- g is not visible here
}
</pre>
<p>
All of this explicit qualification business
can be a bit tedious.
The easiest way to avoid this tedium is to use what is called
a <i>using directive</i>, which effectively makes
all names declared within a namespace visible in the
global scope.
Here is a variation on the previous example, with a using directive.
<p>
<pre>
namespace N {
void f(int);
void g(int);
int x;
}
int x;
using namespace N;
void h()
{
x = 1; // error -- ambiguous: the global x or the x in namespace N?
::x = 1; // the global x
N::x = 0; // the x in namespace N
N::f(0); // the f in namespace N
f(0); // OK -- N::f(int) is visible here
g(1); // OK -- N::g(int) is visible here
}
</pre>
<p>
Here is another example.
<p>
<pre>
namespace N1 {
int x;
void f(int);
void g(int);
}
namespace N2 {
int x;
int y;
void f(double);
void g(int);
}
using namespace N1;
using namespace N2;
void h()
{
x = 1; // error -- ambiguous: N1::x or N2::x?
N1::x = 1; // OK
N2::x = 1; // OK
y = 1; // OK -- this is N2::y
g(0); // error -- ambiguous: N1::g(int) or N2::g(int)?
f(0); // OK -- N1::f(int), because it is the "best" match
f(0.0); // OK -- N2::f(double), because it is the "best" match
}
</pre>
<p>
This example illustrates the interaction between using declarations
and function overloading resolution.
If several overloaded versions of a function are visible,
it is not necessarily ambiguous: the usual overload resolution
procedure is applied, and if there is a unique "best" match,
then there is no ambiguity.
<p>
The examples presented here do not illustrate all of the
features and nuances of namespaces.
For this, you are referred to a <tt>C++</tt> book.
<p>
<h3>
Namespaces and NTL
</h3>
<p>
In ISO mode, the standard library is "wrapped" in namespace <tt>std</tt>,
and NTL is "wrapped" in namespace <tt>NTL</tt>.
Thus, the header file <tt><NTL/ZZ.h></tt> in ISO mode looks
something like this:
<pre>
namespace NTL {
// ...
class ZZ { /* ... */ };
// ...
ZZ operator+(const ZZ& a, const ZZ& b);
ZZ operator*(const ZZ& a, const ZZ& b);
std::istream& operator>>(std::istream& s, ZZ& x);
std::ostream& operator<<(std::ostream& s, const ZZ& a);
// ...
}
</pre>
Therefore, one must explicitly qualify all names, or use appropriate
using directives.
Here is how one could write the <a href="tour-ex1.html">first example</a>
of the tour in
ISO mode.
<pre>
#include <NTL/ZZ.h>
int main()
{
NTL::ZZ a, b, c;
std::cin >> a;
std::cin >> b;
c = (a+1)*(b+1);
std::cout << c << "\n";
}
</pre>
<p>
Notice how everything is explicitly qualified.
Actually, the input/output operators <tt><<</tt> and <tt>>></tt>,
and the arithmetic operators <tt>+</tt> and <tt>*</tt> are not explicitly
qualified, but rather, the compiler finds them through a gimmick
called <i>Koenig Lookup</i>, which will look for functions (and operators)
declared in namespace <tt>NTL</tt>, because the type of the argument
(<tt>ZZ</tt>) is a class declared in that namespace.
<p>
Even with Koenig Lookup, explicit qualification can
be a bit tedious.
Here is the same example, this time with using directives.
<pre>
#include <NTL/ZZ.h>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -