Namespace Support
Namespaces are enabled by default
(this
can be changed in a custom porting arrangement) except in the
cfront modes. The command-line options --namespaces and
--no_namespaces can be used to enable or disable the
features.
Name lookup during template instantiations now does
something that approximates the two-phase lookup rule of the X3J16/WG21
Working Paper. When a name is looked up as part of a template
instantiation but is not found in the local context of the instantiation,
it is looked up in a synthesized instantiation context. The front
end follows the new instantiation lookup rules for namespaces
as closely as possible in the absence of a complete implementation
of the new template name binding rules. Here's an example:
namespace N {
int g(int);
int x = 0;
template <class T> struct A {
T f(T t) { return g(t); }
T f() { return x; }
};
}
namespace M {
int x = 99;
double g(double);
N::A<int> ai;
int i = ai.f(0); // N::A<int>::f(int) calls N::g(int)
int i2 = ai.f(); // N::A<int>::f() returns 0 (= N::x)
N::A<double> ad;
double d = ad.f(0);
// N::A<double>::f(double) calls M::g(double)
double d2 = ad.f();
// N::A<double>::f() also returns 0 (= N::x)
}
The lookup of names in template instantiations does
not conform to the rules in the working paper in the following
respects:
- Although only names from the template definition context are
considered for names that are not functions, the lookup is not
limited to those names visible at the point at which the template
was defined.
- Functions from the context in which the template was referenced
are considered for all function calls in the template. Functions
from the referencing context should only be visible for "dependent"
function calls.
The lookup rules for overloaded operators are implemented as specified
by the Working Paper, which means that the operator functions
in the global scope overload with the operator functions declared
extern inside a function, instead of being hidden by them. The
old operator function lookup rules are used when namespaces are
turned off. This means a program can have different behavior,
depending on whether it is compiled with namespace support enabled
or disabled:
struct A { };
A operator+(A, double);
void f() {
A a1;
A operator+(A, int);
a1 + 1.0; // calls operator+(A, double) with namespaces
} // enabled but otherwise calls operator+(A, int);
The
interaction between friend declarations and namespaces is incompletely
(or incorrectly) specified in the current Working Paper; pending
clarification, we have made the following implementation choices:
- A namespace-qualified friend declaration must refer to a previously
declared entity.
- A globally qualified name is permitted in a friend declaration,
(e.g., friend void ::f();) as an extension; it too must refer
to an existing entity.
- An unqualified friend declaration may be a definition, but
a namespace-qualified friend declaration may not.
- The lookup of an unqualified friend declaration begins in
the innermost nonclass scope and continues no further than the
innermost namespace scope.
The final rule (which for friend declarations in nonlocal classes
effectively requires that the scope for name lookup and the scope
for name injection be the same) prevents a namespace from being
"polluted" by declarations from an enclosing namespace.
For example:
namespace N {
class A {
friend void f();// always declares N::f, regardless
}; // of whether ::f is visible
}
The programmer is assured that f is injected into namespace
N whether or not there is a declaration of f in the scope enclosing
N.
The headers and runtime provided with the Comeau front end
support two different versions (i.e., with and without namespaces)
under control of __EDG_RUNTIME_USES_NAMESPACES, a preprocessing
option defined by the front end.