Section 17.2. Namespaces


17.2. Namespaces

Every name defined in a given scope must be unique within that scope. This requirement can be difficult to satisfy for large, complex applications. Such applications tend to have many names defined in the global scope. Complex programs composed of independently developed libraries are even more likely to encounter name collisionsthe same name is used in our own code or (more often) in the code supplied to us by independent producers.

Libraries tend to define a large number of global namesprimarily names of templates, types and functions. When writing an application using libraries from many different vendors, it is almost inevitable that some of these names will clash. This name-clashing problem is known as the namespace pollution problem.

Traditionally, programmers avoided namespace pollution by making names of global entities very long, often prefixing the names in their program with specific character sequences:

      class cplusplus_primer_Query { ... };      ifstream&      cplusplus_primer_open_file(ifstream&, const string&); 

This solution is far from ideal: It can be cumbersome for programmers to write and read programs that use such long names. Namespaces provide a much more controlled mechanism for preventing name collisions. Namespaces partition the global namespace, making it easier to use independently produced libraries. A namespace is a scope. By defining a library's names inside a namespace, library authors (and users) can avoid the limitations inherent in global names.

17.2.1. Namespace Definitions

A namespace definition begins with the keyword namespace followed by the namespace name.

      namespace cplusplus_primer {          class Sales_item { /* ... */};          Sales_item operator+(const Sales_item&,                               const Sales_item&);          class Query {          public:              Query(const std::string&);              std::ostream &display(std::ostream&) const;              // ...          };          class Query_base { /* ... */};      } 

This code defines a namespace named cplusplus_primer with four members: two classes, an overloaded + operator, and a function.

As with other names, the name of a namespace must be unique within the scope in which the namespace is defined. Namespaces may be defined at global scope or inside another namespace. They may not be defined inside a function or a class.

Following the namespace name is a block of declarations and definitions delimited by curly braces. Any declaration that can appear at global scope can be put into a namespace: classes, variables (with their initializations), functions (with their definitions), templates, and other namespaces.

A namespace scope does not end with a semicolon.



Each Namespace Is a Scope

The entities defined in a namespace are called namespace members. Just as is the case for any scope, each name in a namespace must refer to a unique entity within that namespace. Because different namespaces introduce different scopes, different namespaces may have members with the same name.

Names defined in a namespace may be accessed directly by other members of the namespace. Code outside the namespace must indicate the namespace in which the name is defined:

      cplusplus_primer::Query q =                      cplusplus_primer::Query("hello");      q.display(cout);      // ... 

If another namespace (say, AddisonWesley) also provides a TextQuery class and we want to use that class instead of the one defined in cplusplus_primer, we can do so by modifying our code as follows:

      AddisonWesley::Query q = AddisonWesley::Query("hello");      q.display(cout);      // ... 

Using Namespace Members from Outside the Namespace

Of course, always referring to a namespace member using the qualified name

      namespace_name::member_name 

can be cumbersome. Just as we've been doing for names defined in the std namespace, we can write a using declaration (Section 3.1, p. 78) to obtain direct access to names we know we'll use frequently:

      using cplusplus_primer::Query; 

After this using declaration, our program can use the name Query directly without the cplusplus_primer qualifier. We'll see other ways to simplify access in Section 17.2.4 (p. 720).

Namespaces Can Be Discontiguous

Unlike other scopes, a namespace can be defined in several parts. A namespace is made up of the sum of its separately defined parts; a namespace is cumulative. The separate parts of a namespace can be spread over multiple files. Namespace definitions in different text files are also cumulative. Of course, the usual restriction continues to apply that names are visible only in the files in which they are declared. So, if one part of the namespace requires a name defined in another file, that name must still be declared.

Writing a namespace definition

      namespace namespace_name {      // declarations      } 

either defines a new namespace or adds to an existing one.

If the name namespace_name does not refer to a previously defined namespace, then a new namespace with that name is created. Otherwise, this definition opens an existing namespace and adds these new declarations to that namespace.

Separation of Interface and Implementation

The fact that namespace definitions can be discontiguous means that we can compose a namespace from separate interface and implementation files. Thus, a namespace can be organized in the same way that we manage our own class and function definitions:

  1. Namespace members that define classes and declarations for the functions and objects that are part of the class interface can be put into header files. These headers can be included by files that use namespace members.

  2. The definitions of namepsace members can be put in separate source files.

Organizing our namespaces this way also satisfies the requirement that various entitiesnon-inline functions, static data members, variables, and so forthmay be defined only once in a program. This requirement applies equally to names defined in a namespace. By separating the interface and implementation, we can ensure that the functions and other names we need are defined only once, but the same declaration will be seen whenever the entity is used.

Namespaces that define multiple, unrelated types should use separate files to represent each type that the namespace defines.



Defining the Primer Namespace

Using this strategy for separating interface and implementation, we might define the cplusplus_primer library in several separate files. The declarations for Sales_item and its related functions that we built in Part I (p. 31) would be placed in Sales_item.h, those for the Query classes of Chapter 15 (p. 557) in Query.h, and so on. The corresponding implementation files would be in files such as Sales_item.cc and Query.cc:

      // ---- Sales_item.h ----      namespace cplusplus_primer {          class Sales_item { /* ... */};          Sales_item operator+(const Sales_item&,                               const Sales_item&);          // declarations for remaining functions in the Sales_item interface      }      // ---- Query.h ----      namespace cplusplus_primer {          class Query {          public:              Query(const std::string&);              std::ostream &display(std::ostream&) const;              // ...          };          class Query_base { /* ... */};      }      // ---- Sales_item.cc ----      #include "Sales_item.h"      namespace cplusplus_primer {      // definitions for Sales_item members and overloaded operators      }      // ---- Query.cc ----      #include "Query.h"      namespace cplusplus_primer {          // definitions for Query members and related functions      } 

This program organization gives both the developers and users of our library the needed modularity. Each class is still organized into its own interface and implementation files. A user of one class need not compile names related to the others. We can hide the implementations from our users, while allowing the files Sales_item.cc and user.cc to be compiled and linked into one program without causing any compile-time or link-time error. Developers of the library can work independently on the implementation of each type.

A program using our library would include whichever headers it needed. The names in those headers are defined inside the cplusplus_primer namespace:

      // ---- user.cc ----      // defines the cplusplus_primer::Sales_item class      #include "Sales_item.h"      int main()      {          // ...          cplusplus_primer::Sales_item trans1, trans2;          // ...          return 0;      } 

Defining Namespace Members

Functions defined inside a namespace may use the short form for names defined in the same namespace:

      namespace cplusplus_primer {      // members defined inside the namespace may use unqualified names      std::istream&      operator>>(std::istream& in, Sales_item& s)      {          // ...      } 

It is also possible to define a namespace member outside its namespace definition. We do so in ways that are similar to defining class members outside a class: The namespace declaration of the name must be in scope, and the definition must specify the namespace to which the name belongs:

      // namespace members defined outside the namespace must use qualified names      cplusplus_primer::Sales_item      cplusplus_primer::operator+(const Sales_item& lhs,                                  const Sales_item& rhs)      {          Sales_item ret(lhs);          // ...      } 

This definition should look similar to class member functions defined outside a class. The return type and function name are qualified by the namespace name. Once the fully qualified function name is seen, we are in the scope of the namespace. Thus, references to namespace members in the parameter list and the function body can use unqualified names to reference Sales_item.

Members May Not Be Defined in Unrelated Namespaces

Although a namespace member can be defined outside its namespace definition, there are restrictions on where this definition can appear. Only namespaces enclosing the member declaration can contain its definition. For example, operator+ could be defined in either the cplusplus_primer namespace or at global scope. It may not be defined in an unrelated namespace.

The Global Namespace

Names defined at global scopenames declared outside any class, function, or namespaceare defined inside the global namespace. The global namespace is implicitly declared and exists in every program. Each file that defines entities at global scope adds those names to the global namespace.

The scope operator can be used to refer to members of the global namespace. Because the global namespace is implicit, it does not have a name; the notation

      ::member_name 

refers to a member of the global namespace.

Exercises Section 17.2.1

Exercise 17.13:

Define the bookstore exception classes described in Section 17.1.7 (p. 697) as members of namespace named Bookstore.

Exercise 17.14:

Define Sales_item and its operators inside the Bookstore namespace. Define the addition operator to throw an exception.

Exercise 17.15:

Write a program that uses the Sales_item addition operator and handles any exceptions. Make this program a member of another namespace named MyApp. This program should use the exception classes defined in the Bookstore namespace by the previous exercise.


17.2.2. Nested Namespaces

A nested namespace is a nested scopeits scope is nested within the namespace that contains it. Names in nested namespaces follow the normal rules: Names declared in an enclosing namespace are hidden by declarations of the same name in a nested namespace. Names defined inside a nested namespace are local to that namespace. Code in the outer parts of the enclosing namespace may refer to a name in a nested namespace only through its qualified name.

Nested namespaces can improve the organization of code in a library:

      namespace cplusplus_primer {          // first nested namespace:          // defines the Query portion of the library          namespace QueryLib {              class Query { /* ... */ };              Query operator&(const Query&, const Query&);              // ...          }          // second nested namespace:          // defines the Sales_item portion of the library          namespace Bookstore {              class Item_base { /* ... */ };              class Bulk_item : public Item_base { /* ... */ };              // ...          }      } 

The cplusplus_primer namespace now contains two nested namespaces: the namespaces named QueryLib and Bookstore.

Nested namespaces are useful when a library provider needs to prevent names in each part of a library from colliding with names in other parts of the library.

The name of a member in a nested namespace is formed from the names of the enclosing namespace(s) and the name of the nested namespace. For example, the name of the class declared in the nested namespace QueryLib is

      cplusplus_primer::QueryLib::Query 

Exercises Section 17.2.2

Exercise 17.16:

Organize the programs you have written to answer the questions in each chapter into its own namespace. That is, namespace chapterrefinheritance would contain code for the Query programs and chapterrefalgs would contain the TextQuery code. Using this structure, compile the Query code examples.

Exercise 17.17:

Over the course of this primer, we defined two different classes named Sales_item: the initial simple class defined and used in Part I, and the handle class defined in Section 15.8.1 that interfaced to the Item_base inheritance hierarchy. Define two namespaces nested inside the cplusplus_primer namespace that could be used to distinguish these two class definitions.


17.2.3. Unnamed Namespaces

A namespace may be unnamed. An unnamed namespace is a namespace that is defined without a name. An unnamed namespace begins with the keyword namespace. Following the namespace keyword is a block of declarations delimited by curly braces.

Unnamed namespaces are not like other namespaces; the definition of an unnamed namespace is local to a particular file and never spans multiple text files.



An unnamed namespace may be discontiguous within a given file but does not span files. Each file has its own unnamed namespace.

Unnamed namespaces are used to declare entities that are local to a file. Variables defined in an unnamed namespace are created when the program is started and exist until the program ends.

Names defined in an unnamed namespace are used directly; after all, there is no namespace name with which to qualify them. It is not possible to use the scope operator to refer to members of unnamed namespaces.

Names defined in an unnamed namespace are visible only to the file containing the namespace. If another file contains an unnamed namespace, the namespaces are unrelated. Both unnamed namespaces could define the same name, and the definitions would refer to different entities.

Names defined in an unnamed namespace are found in the same scope as the scope at which the namespace is defined. If an unnamed namespace is defined at the outermost scope in the file, then names in the unnamed namespace must differ from names defined at global scope:

      int i;   // global declaration for i      namespace {          int i;      }      // error: ambiguous defined globally and in an unnested, unnamed namespace      i = 10; 

An unnamed namespace, like any other namespace, may be nested inside another namespace. If the unnamed namespace is nested, then names in it are accessed in the normal way, using the enclosing namespace name(s):

      namespace local {         namespace {             int i;         }      }         // ok: i defined in a nested unnamed namespace is distinct from global i         local::i = 42; 

If a header defines an unnamed namespace then the names in that namespace will define different local entities in each file that includes the header.



In all other ways, the members of an unnamed namespace are normal program entities.

Unnamed Namespaces Replace File Statics

Prior to the introduction of namespaces in standard C++, programs had to declare names as static to make them local to a file. The use of file statics is inherited from C. In C, a global entity declared static is invisible outside the file in which it is declared.

The use of file static declarations is deprecated by the C++ standard. A deprecated feature is one that may not be supported in future releases. File statics should be avoided and unnamed namespaces used instead.




Exercises Section 17.2.3

Exercise 17.18:

Why would you define your own namespace in your programs? When might you use an unnamed namespace?

Exercise 17.19:

Suppose we have the following declaration of the operator* that is a member of the nested namespace cplusplus_primer::MatrixLib:

      namespace cplusplus_primer {          namespace MatrixLib {              class matrix { /* ... */ };              matrix operator*                     (const matrix &, const matrix &);              // ...          }      } 

How would you define this operator in global scope? Provide only the prototype for the operator's definition.


17.2.4. Using Namespace Members

Referring to namespace members as namespace_name::member_name is admittedly cumbersome, especially if the namespace name is long. Fortunately, there are ways to make it easier to use namespace members. Our programs have used one of these ways, using declarations (Section 3.1, p. 78). The others, namespace aliases and using directives, will be described in this section.

Header files should not contain using directives or using declarations except inside functions or other scopes. A header that includes a using directive or declaration at its top level scope has the effect of injecting that name into the file that includes the header. Headers should define only the names that are part of its interface, not names used in its own implementation.



using Declarations, a Recap

The programs in this book that use names from the standard library generally assume that an appropriate using declaration has been made:

      map<string, vector< pair<size_t, size_t> > > word_map; 

assumes that the following using declarations have been made:

      using std::map;      using std::pair;      using std::size_t;      using std::string;      using std::vector; 

A using declaration introduces only one namespace member at a time. It allows us to be very specific regarding which names are used in our programs.

Scope of a using Declaration

Names introduced in a using declaration obey normal scope rules. The name is visible from the point of the using declaration to the end of the scope in which the declaration is found. Entities with the same name defined in an outer scope are hidden.

The shorthand name may be used only within the scope in which it is declared and in scopes nested within that scope. Once the scope ends, the fully qualified name must be used.

A using declaration can appear in global, local, or namespace scope. A using declaration in class scope is limited to names defined in a base class of the class being defined.

Namespace Aliases

A namespace alias can be used to associate a shorter synonym with a namespace name. For example, a long namespace name such as

      namespace cplusplus_primer { /* ... */ }; 

can be associated with a shorter synonym as follows:

      namespace primer = cplusplus_primer; 

A namespace alias declaration begins with the keyword namespace, followed by the (shorter) name of the namespace alias, followed by the = sign, followed by the original namespace name and a semicolon. It is an error if the original namespace name has not already been defined as a namespace.

A namespace alias can also refer to a nested namespace. Rather than writing

      cplusplus_primer::QueryLib::Query tq; 

we could define and use an alias for cplusplus_primer::QueryLib:

      namespace Qlib = cplusplus_primer::QueryLib;      Qlib::Query tq; 

A namespace can have many synonyms, or aliases. All the aliases and the original namespace name can be used interchangeably.



using Directives

Like a using declaration, a using directive allows us to use the shorthand form of a namespace name. Unlike a using declaration, we retain no control over which names are made visiblethey all are.

The Form of a using Directive

A using directive begins with the keyword using, followed by the keyword namespace, followed by a namespace name. It is an error if the name is not a previously defined namespace name.

A using directive makes all the names from a specific namespace visible without qualification. The short form names can be used from the point of the using directive to the end of the scope in which the using directive appears.

A using directive may appear in namespace, function, or block scope. It may not appear in a class scope.

It can be tempting to write programs with using directives, but doing so reintroduces all the problems inherent in name collisions when using multiple libraries.



using Directives and Scope

The scope of names introduced by a using directive is more complicated than those for using declarations. A using declaration puts the name directly in the same scope in which the using declaration itself appears. It is as if the using declaration is a local alias for the namespace member. Because the declaration is localized, the chance of collisions is minimized.

A using directive does not declare local aliases for the namespace member names. Rather, it has the effect of lifting the namespace members into the nearest scope that contains both the namespace itself and the using directive.



In the simplest case, assume we have a namespace A and a function f, both defined at global scope. If f has a using directive for A, then in f it will be as if the names in A appeared in the global scope prior to the definition of f:

     // namespace A and function f are defined at global scope     namespace A {         int i, j;     }     void f()     {         using namespace A;      // injects names from A into the global scope         cout << i * j << endl; // uses i and j from namespace A         //...     } 

One place where using directives are useful is in the implementation files for the namespace itself.



using Directives Example

Let's look at an example:

     namespace blip {         int bi = 16, bj = 15, bk = 23;         // other declarations     }     int bj = 0; // ok: bj inside blip is hidden inside a namespace     void manip()     {          // using directive - names in blip "added" to global scope          using namespace blip;                          // clash between ::bj and blip::bj                          // detected only if bj is used          ++bi;           // sets blip::bi to 17          ++bj;           // error: ambiguous                          // global bj or blip::bj?          ++::bj;         // ok: sets global bj to 1          ++blip::bj;     // ok: sets blip::bj to 16          int bk = 97;    // local bk hides blip::bk          ++bk;           // sets local bk to 98     } 

The using directive in manip makes all the names in blip directly accessible to manip: The function can refer to the names of these members, using their short form.

The members of blip appear as if they were defined in the scope in which both blip and manip are defined. Given that blip is defined at global scope, then the members of blip appear as if they were declared in global scope. Because the names are in different scopes, local declarations within manip may hide some of the namespace member names. The local variable bk hides the namespace member blip::bk. Referring to bk within manip is not ambiguous; it refers to the local variable bk.

It is possible for names in the namespace to conflict with other names defined in the enclosing scope. For example, the blip member bj appears to manip as if it were declared at global scope. However, there is another object named bj in global scope. Such conflicts are permitted; but to use the name, we must explicitly indicate which version is wanted. Therefore, the use of bj within manip is ambiguous: The name refers both to the global variable and to the member of namespace blip.

To use a name such as bj, we must use the scope operator to indicate which name is wanted. We would write ::bj to obtain the variable defined in global scope. To use the bj defined in blip, we must use its qualified name, blip::bj.

Exercises Section 17.2.4

Exercise 17.20:

Explain the differences between using declarations and using directives.

Exercise 17.21:

Consider the following code sample:

     namespace Exercise {         int ivar = 0;         double dvar = 0;         const int limit = 1000;     }     int ivar = 0;     // position 1     void manip() {          // position 2          double dvar = 3.1416;          int iobj = limit + 1;          ++ivar;          ++::ivar;     } 

What are the effects of the declarations and expressions in this code sample if using declarations for all the members of namespace Exercise are located at the location labeled position 1? At position 2 instead? Now answer the same question but replace the using declarations with a using directive for namespace Exercise.


Caution: Avoid Using Directives

using directives, which inject all the names from a namespace, are deceptively simple to use: With only a single statement, all the member names of a namespace are suddenly visible. Although this approach may seem simple, it can introduce its own problems. If an application uses many libraries, and if the names within these libraries are made visible with using directives, then we are back to square one, and the global namespace pollution problem reappears.

Moreover, it is possible that a working program will fail to compile when a new version of the library is introduced. This problem can arise if a new version introduces a name that conflicts with a name that the application is using.

Another problem is that ambiguity errors caused by using directives are detected only at the point of use. This late detection means that conflicts can arise long after introducing a particular library. If the program begins using a new part of the library, previously undetected collisions may arise.

Rather than relying on a using directive, it is better to use a using declaration for each namespace name used in the program. Doing so reduces the number of names injected into the namespace. Ambiguity errors caused by using declarations are detected at the point of declaration, not use, and so are easier to find and fix.


17.2.5. Classes, Namespaces, and Scope

As we've noted, namespaces are scopes. As in any other scope, names are visible from the point of their declaration. Names remain visible through any nested scopes until the end of the block in which they were introduced.

Name lookup for names used inside a namespace follows the normal C++ lookup rules: When looking for a name, we look outward through the enclosing scopes. An enclosing scope for a name used inside a namespace might be one or more nested namespaces ending finally with the all-encompassing global namespace. Only names that have been declared before the point of use that are in blocks that are still open are considered:

     namespace A {         int i;         namespace B {             int i;        // hides A::i within B             int j;             int f1()             {                 int j;    // j is local to f1 and hides A::B::j                 return i; // returns B::i             }         } // namespace B is closed and names in it are no longer visible         int f2() {            return j;     // error: j is not defined         }         int j = i;      // initialized from A::i     } 

Names used in a class member definition are resolved in much the same way, with one important difference: If the name is not local to the member function, we first try to resolve the name to a class member before looking in the outer scopes.

As we saw in Section 12.3 (p. 444), members defined inside a class may use names that appear textually after the definition. For example, a constructor defined inside the class body may initialize the data members even if the declaration of those members appears after the constructor definition. When a name is used in a class scope, we look first in the member itself, then in the class, including any base classes. Only after exhausting the class(es) do we examine the enclosing scopes. When a class is wrapped in a namespace, the same lookup happens: Look first in the member, then the class (including base classes), then look in the enclosing scopes, one or more of which might be a namespace:

     namespace A {         int i;         int k;         class C1 {         public:             C1(): i(0), j(0) { }   // ok: initializes C1::i and C1::j             int f1()             {                  return k;        // returns A::k             }             int f2()             {                 return h;        // error: h is not defined             }             int f3();         private:            int i;                // hides A::i within C1            int j;         };         int h = i;               // initialized from A::i      }      // member f3 is defined outside class C1 and outside namespace A      int A::C1::f3()      {          return h;               // ok: returns A::h      } 

With the exception of member definitions, scopes are always searched upward: A name must be declared before it can be used. Hence, the return in f2 will not compile. It attempts to reference the name h from namespace A, but h has not yet been defined. Had that name been defined in A before the definition of C1, the use of h would be legal. Similarly, the use of h inside f3 is okay, because f3 is defined after A::h has been defined.

The order in which scopes are examined to find a name can be inferred from the qualified name of a function. The qualified name indicates, in reverse order, the scopes that are searched.



The qualifiers A::C1::f3 indicate the reverse order in which the class scopes and namespace scopes are to be searched. The first scope searched is that of the function f3. Then the class scope of its enclosing class C1 is searched. The scope of the namespace A is searched last before the scope containing the definition of f3 is examined.

Argument-Dependent Lookup and Class Type Parameters

Consider the following simple program:

     std::string s;     // ok: calls std::getline(std::istream&, const std::string&)     getline(std::cin, s); 

The program uses the std::string type, yet it refers without qualification to the getline function. Why can we use this function without a specific std:: qualifier or a using declaration?

It turns out that there is an important exception to the rule that namespace names are hidden.

Functions, including overloaded operators, that take parameters of a class type (or pointer or reference to a class type), and that are defined in the same namespace as the class itself, are visible when an object of (or reference or pointer to) the class type is used as an argument.



When the compiler sees the use of the getline function

     getline(std::cin, s); 

it looks for a matching function in the current scope, the scopes enclosing the call to getline, and in the namespace(s) in which the type of cin and the string type are defined. Hence, it looks in the namespace std and finds the getline function defined by the string type.

The reason that functions are made visible if they have a parameter of the class type is to allow nonmember functions that are conceptually part of a class' interface to be used without requiring a separate using declaration. Being able to use nonmember operations is particularly useful for operator functions.

For example, consider the following simple program:

     std::string s;     cin >> s; 

In absence of this exception to the lookup rules, we would have to write either:

     using std::operator>>;        // need to allow cin >> s     std::operator>>(std::cin, s); // ok: explicitly use std::>> 

Either of these declarations is awkward and would make simple uses of strings and the IO library more complicated.

Implicit Friend Declarations and Namespaces

Recall that when a class declares a friend function (Section 12.5, p. 465), a declaration for the function need not be visible. If there isn't a declaration already visible, then the friend declaration has the effect of putting a declaration for that function or class into the surrounding scope. If a class is defined inside a namespace, then an otherwise undeclared friend function is declared in the same namespace:

     namespace A {         class C {             friend void f(const C&); // makes f a member of namespace A         };     } 

Because the friend takes an argument of a class type and is implicitly declared in the same namespace as the class, it can be used without using an explicit name-space qualifier:

     // f2 defined at global scope     void f2()     {          A::C cobj;          f(cobj); // calls A::f     } 

17.2.6. Overloading and Namespaces

As we've seen, each namespace maintains its own scope. As a consequence, functions that are members of two distinct namespaces do not overload one another. However, a given namespace can contain a set of overloaded function members.

In general, function matching (Section 7.8.2, p. 269) within a namespace happens in the same manner as we've already seen:

  1. Find the set of candidate functions. A function is a candidate if a declaration for it is visible at the time of the call and if it has the same name as the called function.

  2. Select the viable functions from the set of candidates. A function is viable if it has the same number of parameters as the call has arguments and if each parameter could be matched by the corresponding argument.

  3. Select the single best match from the viable set and generate code to call that function. If the viable set is empty, then the call is in error, having no match. If the viable set is nonempty and there is no best match, then the call is ambiguous.

Candidate Functions and Namespaces

Namespaces can have two impacts on function matching. One of these should be obvious: A using declaration or directive can add functions to the candidate set. The other is much more subtle.

As we saw in the previous section, name lookup for functions that have one or more class-type parameters includes the namespace in which each parameter's class is defined. This rule also impacts how we determine the candidate set. Each namespace that defines a class used as a parameter (and those that define its base class(es)) is searched for candidate functions. Any functions in those namespaces that have the same name as the called function are added to the candidate set. These functions are added even though they otherwise are not visible at the point of the call. Functions with the matching name in those namespaces are added to the candidate set:

     namespace NS {         class Item_base { /* ... */ };         void display(const Item_base&) { }     }     // Bulk_item's base class is declared in namespace NS     class Bulk_item : public NS::Item_base { };     int main() {         Bulk_item book1;         display(book1);         return 0;     } 

The argument, book1, to the display function has class type Bulk_item. The candidate functions for the call to display are not only the functions with declarations that are visible where the function display is called, but also the functions in the namespace where the class Bulk_item and its base class Item_base are declared. The function display(const Item_base&) declared in namespace NS is added to the set of candidate functions.

Overloading and using Declarations

A using declaration declares a name. As we saw in Section 15.5.3 (p. 592), there is no way to write a using declaration to refer to a specific function declaration:

     using NS::print(int); // error: cannot specify parameter list     using NS::print;      // ok: using declarations specify names only 

If a function is overloaded within a namespace, then a using declaration for the name of that function declares all the functions with that name. If there are print functions for int and double in the namespace NS, then a using declaration for NS::print makes both functions visible in the current scope.

A using declaration incorporates all versions of an overloaded function to ensure that the interface of the namespace is not violated. The author of a library provided different functions for a reason. Allowing users to selectively ignore some but not all of the functions from a set of overloaded functions could lead to surprising program behavior.

The functions introduced by a using declaration overload any other declarations of the functions with the same name already present in the scope where the using declaration appears.

If the using declaration introduces a function in a scope that already has a function of the same name with the same parameter list, then the using declaration is in error. Otherwise, the using declaration defines additional overloaded instances of the given name. The effect is to increase the set of candidate functions.

Overloading and using Directives

A using directive lifts the namespace members into the enclosing scope. If a namespace function has the same name as a function declared in the scope at which the namespace is placed, then the namespace member is added to the overload set:

     namespace libs_R_us {         extern void print(int);         extern void print(double);     }     void print(const std::string &);     // using directive:     using namespace libs_R_us;     // using directive added names to the candidate set for calls to print:     // print(int) from libs_R_us     // print(double) from libs_R_us     // print(const std::string &) declared explicitly     void fooBar(int ival)     {          print("Value: "); // calls global print(const string &)          print(ival);      // calls libs_R_us::print(int)     } 

Overloading across Multiple using Directives

If many using directives are present, then the names from each namespace become part of the candidate set:

     namespace AW {         int print(int);     }     namespace Primer {         double print(double);     }     // using directives:     // form an overload set of functions from different namespaces     using namespace AW;     using namespace Primer;     long double print(long double);     int main() {         print(1);   // calls AW::print(int)         print(3.1); // calls Primer::print(double)         return 0;     } 

The overload set for the function print in global scope contains the functions print(int), print(double), and print(long double). These functions are all part of the overload set considered for the function calls in main, even though these functions were originally declared in different namespace scopes.

Exercises Section 17.2.6

Exercise 17.22:

Given the following code, determine which function, if any, matches the call to compute. List the candidate and viable functions. What type conversion sequence, if any, is applied to the argument to match the parameter in each viable function?

     namespace primerLib {         void compute();         void compute(const void *);     }     using primerLib::compute;     void compute(int);     void compute(double, double = 3.4);     void compute(char*, char* = 0);     int main()     {         compute(0);         return 0;     } 

What would happen if the using declaration were located in main before the call to compute? Answer the same questions as before.


17.2.7. Namespaces and Templates

Declaring a template within a namespace impacts how template specializations (Section 16.6, p. 671) are declared: An explicit specialization of a template must be declared in the namespace in which the generic template is defined. Otherwise, the specialization would have a different name than the template it specialized.

There are two ways to define a specialization: One is to reopen the namespace and add the definition of the specialization, which we can do because namespace definitions are discontiguous, Alternatively, we could define the specialization in the same way that we can define any namespace member outside its namespace definition: by defining the specialization using the template name qualified by the name of the namespace.

To provide our own specializations of templates defined in a namespace, we must ensure that the specialization definition is defined as being in the namespace containing the original template definition.





C++ Primer
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2006
Pages: 223
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net