概述
Please indicate the source: http://blog.csdn.net/gaoxiangnumber1
Welcome to my github: https://github.com/gaoxiangnumber1
18.2. Namespaces
- Libraries that put names into the global namespace are said to cause namespace pollution.
- Traditional solution is using long names that often contained a prefix indicating which library defined the name for the global entities.
class cpp_primer_Query { ... };
string cpp_primer_make_plural(size_t, string&);
- A namespace is a scope and it partition the global namespace. By defining a library’s names inside a namespace, library authors and users can avoid the limitations inherent in global names.
18.2.1. Namespace Definitions
- A namespace definition begins with the keyword
namespace
followed by the namespace name, followed by a sequence of declarations and definitions delimited by curly braces. A namespace scope does not end with a semicolon. - 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.
namespace cpp_primer
{
class Sales_data { /* ... */ };
Sales_data operator+(const Sales_data&, const Sales_data&);
class Query { /* ... */ };
class Query_base { /* ... */ };
} // namespaces do not end with a semicolon
- A namespace name 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.
Each Namespace Is a Scope
- Each name in a namespace must refer to a unique entity within that namespace, different namespaces may have members with the same name.
- Names defined in a namespace may be accessed directly by other members of the namespace, including scopes nested within those members. Code outside the namespace must indicate the namespace in which the name is defined.
cpp_primer::Query q = cpp_primer::Query("hello");
- If another namespace(say, xiang) also provides a Query class and we want to use it:
xiang::Query q = xiang::Query("hello");
Namespaces Can Be Discontiguous
namespace example
{
// declarations
}
- A namespace can be defined in several parts. A namespace definition either defines a new namespace or adds to an existing one.
- If the name
example
does not refer to a previously defined namespace, then a new namespace with that name is created. - Otherwise, this definition adds declarations to that already existing namespace.
- If the name
- A namespace can be organized in the same way that we manage class and function definitions:
- 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 those namespace members.
- The definitions of namespace members can be put in separate source files.
- Organizing namespaces in this way satisfies the requirement that various entities (non-inline functions, static data members, variables, and so forth) may be defined only once in a program. 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(or each collection of related types) that the namespace defines.
Defining the Primer Namespace
- The declarations for Sales_data and its related functions would be placed in Sales_data.h; the corresponding implementation would be in Sales_data.cc:
// ---- Sales_data.h----
// #includes should appear before opening the namespace
#include <string>
namespace cpp_primer
{
class Sales_data { /* ... */ };
Sales_data operator+(const Sales_data&, const Sales_data&);
// declarations for the remaining functions in the Sales_data interface
}
// ---- Sales_data.cc----
// be sure any #includes appear before opening the namespace
#include "Sales_data.h"
namespace cpp_primer
{
// definitions for Sales_data members and overloaded operators
}
- A program using our library should include headers it needed. The names in those headers are defined in the cpp_primer namespace.
// ---- user.cc----
// names in the Sales_data.h header are in the cpp_primer namespace
#include "Sales_data.h"
int main()
{
using cpp_primer::Sales_data;
Sales_data trans1, trans2;
// ...
return 0;
}
- Each class is 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_data.cc and user.cc to be compiled and linked into one program without causing any compile-time or link-time errors.
- We shouldn’t put
#include
inside the namespace. If we did, we attempt to define all the names in that header as members of the enclosing namespace. For example, if Sales_data.h file opened the cpp_primer before including the string header, our program would be attempting to define the std namespace nested inside cpp_primer, which would be an error
Defining Namespace Members
- Assuming the appropriate declarations are in scope, code inside a namespace may use the short form for names defined in the same(or in an enclosing) namespace.
#include "Sales_data.h"
namespace cpp_primer // reopen cpp_primer
{
// members defined inside the namespace may use unqualified names
std::istream& operator>>(std::istream& in, Sales_data& s) { /* ... */ }
}
- When we define a member outside its namespace definition, 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
cpp_primer::Sales_data
cpp_primer::operator+(const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data ret(lhs);
// ...
}
- After the qualified name is seen, we are in the scope of the namespace, so we can use other namespace member names without qualification.
- Namespace member’s definition that is outside its namespace must appear in an enclosing namespace. That is, we can define the
Sales_data operator+
inside the cpp_primer namespace or at global scope; we cannot define it in an unrelated namespace.
Template Specializations
- Template specializations must be defined in the same namespace that contains the original template(16.5). After we have declared the specialization inside the namespace, we can define it outside the namespace.
// we must declare the specialization as a member of std
namespace std
{
template <> struct hash<Sales_data>;
}
// having added the declaration for the specialization to std
// we can define the specialization outside the std namespace
template <> struct std::hash<Sales_data>
{
size_t operator()(const Sales_data& s) const
{
return hash<string>()(s.bookNo) ^
hash<unsigned>()(s.units_sold) ^
hash<double>()(s.revenue);
}
// other members as before
};
The Global Namespace
- Names defined at global scope(i.e., names declared outside any class, function, or namespace) are defined inside the global namespace. The global namespace is implicitly declared and exists in every program. Each file that defines entities at global scope implicitly adds those names to the global namespace.
- The global namespace does not have a name;
::member_name
refers to a member of the global namespace.
Nested Namespaces
namespace cpp_primer
{
// first nested namespace: defines the Query portion of the library
namespace Query
{
class Query { /* ... */ };
Query operator&(const Query&, const Query&);
// ...
}
// second nested namespace: defines the Sales_data portion of the library
namespace Bookstore
{
class Quote { /* ... */ };
class Disc_quote : public Quote { /* ... */ };
// ...
}
}
- A nested namespace is a namespace defined inside another namespace, and its scope is nested in the namespace that contains it.
- Names declared in an inner namespace hide declarations of the same name in an outer namespace. Names defined inside a nested namespace are local to that inner namespace.
- Code in the outer parts of the enclosing namespace may refer to a name in a nested namespace only through its qualified name:
cpp_primer::Query::Query
Inline Namespaces(C++11)
inline namespace Fifth
{
// namespace for the code from the Primer Fifth Edition
}
namespace Fifth // implicitly inline
{
class Query_base { /* ... */ };
// other Query-related declarations
}
- An inline namespace is defined by preceding the keyword
namespace
with the keywordinline
.
The keyword must appear on the first definition of the namespace. If the namespace is later reopened, the keywordinline
need not be, but may be, repeated. - Unlike other nested namespaces, names in an inline namespace can be used as if they were direct members of the enclosing namespace, i.e., we can access them using only the name of the enclosing namespace.
- Inline namespaces are often used when code changes from one release of an application to the next. For example, we can put all the code from the current edition of the Primer into an inline namespace. Code for previous versions would be in non-inlined namespaces:
namespace Fourth
{
class Item_base { /* ... */ };
class Query_base { /* ... */ };
// other code from the Fourth Edition
}
- The overall cpp_primer namespace would include the definitions of both namespaces. Assuming each namespace was defined in a header with the corresponding name, we’d define cpp_primer as follows.
namespace cpp_primer
{
#include "Fifth.h"
#include "Fourth.h"
}
- Because Fifth is inline, code that refers to
cpp_primer::
will get the version from that namespace. If we want the earlier edition code, we can access it by using the names of all the enclosing namespaces:cpp_primer::Fourth::Query_base
.
Unnamed Namespaces
- An unnamed namespace is the keyword
namespace
followed immediately by a block of declarations delimited by curly braces. Variables defined in an unnamed namespace have static lifetime: they are created before their first use and destroyed when the program ends. - An unnamed namespace may be discontiguous within a given file but does not span files. Each file has its own unnamed namespace. If two files contain unnamed namespaces, those namespaces are unrelated. Both unnamed namespaces can define the same name; those definitions would refer to different entities. If a header defines an unnamed namespace, the names in that namespace define different entities local to each file that includes the header.
- Names defined in an unnamed namespace are used directly. It is impossible to use the scope operator to refer to members of unnamed namespaces.
- Names defined in an unnamed namespace are 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;
}
// ambiguous: defined globally and in an un-nested, unnamed namespace
i = 10;
- An unnamed 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;
Unnamed Namespaces Replace File Statics
- Prior to the introduction of namespaces, programs declared names as
static
to make them local to a file. The use of file statics is inherited from C. In C, a global entity declaredstatic
is invisible outside the file in which it is declared. - The use of file static declarations is deprecated by the C++ standard. File statics should be avoided and unnamed namespaces used instead.
Exercises Section 18.2.1
Exercise 18.12
Organize the programs you have written to answer the questions in each chapter into their own namespaces. That is, namespace chapter15 would contain code for the Query programs and chapter10 would contain the TextQuery code. Using this structure, compile the Query code examples.
- Omit.
Exercise 18.13
When might you use an unnamed namespace?
- http://stackoverflow.com/questions/154469/unnamed-anonymous-namespaces-vs-static-functions
- http://stackoverflow.com/questions/5312213/uses-of-unnamed-namespace-in-c
Exercise 18.14
Suppose we have the following declaration of the operator* that is a member of the nested namespace math::Matrix:
namespace math
{
namespace Matrix
{
class matrix { /* ... */ };
matrix operator* (const matrix &, const matrix &);
// ...
}
}
How would you declare this operator in global scope?
math::Matrix::matrix math::Matrix::operator*(const matrix &, const matrix &);
18.2.2. Using Namespace Members
Namespace Aliases
- Namespace alias declaration syntax:
namespace alias_name = original_name;
. It is an error if the original namespace name has not already been defined as a namespace.
namespace cpp_primer{ /* ... */ };
namespace primer = cpp_primer;
- A namespace alias can refer to a nested namespace.
namespace lib = cpp_primer::Query;
lib::Query q;
- A namespace can have many synonyms, or aliases. All the aliases and the original namespace name can be used interchangeably.
using Declarations: A Recap
- A using declaration introduces one namespace member at a time. Names introduced in a using declaration are visible from the point of the using declaration to the end of the scope in which the declaration appears. Entities with the same name defined in an outer scope are hidden. The unqualified 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, namespace, or class scope. In class scope, such declarations may only refer to a base class member(15.5).
using Directives
- Using directive syntax:
using namespace namespace_name;
. It is an error if the name is not a previously defined namespace name. A using directive may appear in global, local, or namespace scope. It may not appear in a class scope. - Using directives make 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.
using Directives and Scope
-
- Using declaration makes name directly accessible in the local scope.
- Using directive makes the entire contents of a namespace available. Since a namespace might include definitions that cannot appear in a local scope, a using directive is treated as if it appeared in the nearest enclosing namespace scope.
- Assume namespace A and 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 the names from A into the global scope
cout << i * j << endl;
// uses i and j from namespace A
// ...
}
using Directives Example
namespace blip
{
int i = 16, j = 15, k = 23;
// other declarations
}
int j = 0; // ok: j inside blip is hidden inside a namespace
void fun()
{
// using directive: the names in blip are added to the global scope
using namespace blip;
// clash between ::j and blip::j detected only if j is used
++i;
// sets blip::i to 17
++j;
// error: global j or blip::j
++::j;
// ok: sets global j to 1
++blip::j;
// ok: sets blip::j to 16
int k = 97; // local k hides blip::k
++k;
// sets local k to 98
}
- The using directive in fun makes all the names in blip directly accessible by using their short form.
- When a namespace is injected into an enclosing scope, it is possible for names in the namespace to conflict with other names defined in that enclosing scope. Inside fun, blip::j conflicts with ::j, we must explicitly indicate which version is wanted to use the name. Any unqualified use of j within fun is error.
- Because the names are in different scopes, local declarations within fun can hide the namespace member names. The local variable k hides the namespace member blip::k. Referring to k within fun refers to the local variable k.
Headers and using Declarations or Directives
- A header that has a using directive or declaration at its top-level scope injects names into every file that includes the header. Headers should define only the names that are part of its interface, not names used in its own implementation. Header files should not contain using directives or using declarations except inside functions or namespaces(3.1).
Caution: Avoid using Directives
- using directives inject all the names from a namespace. If an application use using directives to make many libraries it used visible, then the global namespace pollution problem appears.
- 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, which 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.
- 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.
- One place where using directives are useful is in the implementation files of the namespace itself.
Exercises Section 18.2.2
Exercise 18.15
Explain the differences between using declarations and directives.
-
- Using declaration makes name directly accessible in the local scope.
- Using directive makes the entire contents of a namespace available. Since a namespace might include definitions that cannot appear in a local scope, a using directive is treated as if it appeared in the nearest enclosing namespace scope.
Exercise 18.16
Explain the following code: assuming using declarations for all the members of namespace Exercise are located at the location labeled position 1. What if they appear at position 2 instead? Now answer the same question but replace the using declarations with a using directive for namespace Exercise.
namespace Exercise
{
int i = 0;
double d = 0;
const int limit = 1000;
}
int i = 0;
// position 1
void fun()
{
// position 2
double d = 3.1416;
int i2 = limit + 1;
++i;
++::i;
}
- See 18.17.
Exercise 18.17
Write code to test your answers to the previous question.
#include <iostream>
namespace Exercise
{
int i = 0;
double d = 0;
const int limit = 1000;
}
int i = 0;
//using Exercise::i;//error: ‘i’ is already declared in this scope
using Exercise::d;
using Exercise::limit;
void fun()
{
double d = 3.1416;
int i2 = limit + 1;
++i;
++::i;
std::cout << "Exercise:: i = " << Exercise::i << ", d = " << Exercise::d << ", limit = "
<< Exercise::limit << 'n';
std::cout << "Global:: i = " << ::i << 'n';
std::cout << "Local:: d = " << d << ", i2 = " << i2 << 'n';
}
int main()
{
fun();
}
/*
Exercise:: i = 0, d = 0, limit = 1000
Global:: i = 2
Local:: d = 3.1416, i2 = 1001
*/
#include <iostream>
namespace Exercise
{
int i = 0;
double d = 0;
const int limit = 1000;
}
int i = 0;
void fun()
{
using Exercise::i;
using Exercise::d;
using Exercise::limit;
//double d = 3.1416; //error: redeclaration of ‘double d’
int i2 = limit + 1;
++i;
++::i;
std::cout << "Exercise:: i = " << Exercise::i << ", d = " << Exercise::d << ", limit = "
<< Exercise::limit << 'n';
std::cout << "Global:: i = " << ::i << 'n';
std::cout << "Local:: d = " << d << ", i2 = " << i2 << 'n';
}
int main()
{
fun();
}
/*
Exercise:: i = 1, d = 0, limit = 1000
Global:: i = 1
Local:: d = 0, i2 = 1001
*/
#include <iostream>
namespace Exercise
{
int i = 0;
double d = 0;
const int limit = 1000;
}
int i = 0;
using namespace Exercise;
void fun()
{
double d = 3.1416;
int i2 = limit + 1;
//++i; //error: reference to ‘i’ is ambiguous
++::i;
std::cout << "Exercise:: i = " << Exercise::i << ", d = " << Exercise::d << ", limit = "
<< Exercise::limit << 'n';
std::cout << "Global:: i = " << ::i << 'n';
std::cout << "Local:: d = " << d << ", i2 = " << i2 << 'n';
}
int main()
{
fun();
}
/*
Exercise:: i = 0, d = 0, limit = 1000
Global:: i = 1
Local:: d = 3.1416, i2 = 1001
*/
#include <iostream>
namespace Exercise
{
int i = 0;
double d = 0;
const int limit = 1000;
}
int i = 0;
void fun()
{
using namespace Exercise;
double d = 3.1416;
int i2 = limit + 1;
//++i; //error: reference to ‘i’ is ambiguous
++::i;
std::cout << "Exercise:: i = " << Exercise::i << ", d = " << Exercise::d << ", limit = "
<< Exercise::limit << 'n';
std::cout << "Global:: i = " << ::i << 'n';
std::cout << "Local:: d = " << d << ", i2 = " << i2 << 'n';
}
int main()
{
fun();
}
/*
Exercise:: i = 0, d = 0, limit = 1000
Global:: i = 1
Local:: d = 3.1416, i2 = 1001
*/
18.2.3. Classes, Namespaces, and Scope
- Name lookup for names used inside a namespace follows the normal lookup rules: The search looks outward through the enclosing scopes. An enclosing scope might be one or more nested namespaces, ending in 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
}
- When a class is wrapped in a namespace, the normal lookup still happens: When a name is used by a member function, look for that name in the member first, then within 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
}
- Except the member function definitions that appear inside the class body(7.4.1), scopes are always searched upward; names must be declared before they can be used.
- The return in f2 can’t compile since it references the name h from namespace A, but h has not yet been defined.
- The use of h inside f3 is okay since f3 is defined after A::h.
- The order in which scopes are examined to find a name is the reverse order of the qualified name of a function(A::C1::f3).
Argument-Dependent Lookup and Parameters of Class Type
std::string s;
std::cin >> s;
// Equivalent to:
operator>>(std::cin, s);
- This
operator>>
function is defined by the string library, which in turn is defined in the std namespace. But we can we calloperator>>
without anstd::
qualifier and without ausing
declaration. - Exception to the rule that names defined in a namespace are hidden:
When we pass an object of a class type to a function, the compiler searches the namespace in which the arguments class is defined in addition to the normal scope lookup. This exception also applies for calls that pass pointers or references to a class type. - When the compiler sees the call to
operator>>
, it looks for a matching function in the current scope, including the scopes enclosing the output statement. Because the >> expression has parameters of class type, the compiler also looks in the namespace(s) in which the types of cin and s are defined. So, the compiler looks in the std namespace, which defines the istream and string types. When it searches std, the compiler finds the string output operator function. - This exception allows nonmember functions that are conceptually part of the interface to a class to be used without requiring a separate using declaration. Without this exception, either we have to provide an using declaration for the output operator:
using std::operator>>;// needed to allow cin >> s
or we have to use the function-call notation in order to include the namespace qualifier:
std::operator>>(std::cin, s); // ok: explicitly use std::>>
Lookup and std::move and std::forward
- Ordinarily, if an application defines a name that is also defined in the library, one of two things is true:
- Normal overloading determines correctly whether a particular call is intended for the application version or the one from the library.
- The application never intends to use the library function.
- Both the library move and forward functions are template functions and the library defines versions of them that have a single rvalue reference function parameter. In a function template, an rvalue reference parameter can match any type (16.2.6).
If we defines a function named move that takes a single parameter, then our move collide with the library version. Similarly for forward. - We suggest always using the fully qualified versions of these names(12.1.5). So long as write
std::move
rather thanmove
, we know that we will get the version from the standard library.
Friend Declarations and Argument-Dependent Lookup
- When a class declares a friend, the friend declaration does not make the friend visible (7.2.1). But an undeclared class or function that is first named in a friend declaration is assumed to be a member of the closest enclosing namespace. The combination of this rule and argument-dependent lookup can lead to surprises.
namespace A
{
class C
{
// two friends; neither is declared apart from a friend declaration
// these functions implicitly are members of namespace A
friend void f(const C&);
// found by argument-dependent lookup
friend void f2();
// won't be found, unless otherwise declared
};
}
- Both f and f2 are members of namespace A. Through argument-dependent lookup, we can call f even if there is no additional declaration for f.
int main()
{
A::C c;
f(c); // ok: finds A::f through the friend declaration in A::C
f2(); // error: A::f2 not declared
}
- Because f takes an argument of a class type, and f is implicitly declared in the same namespace as C, f is found when called.
Because f2 has no parameter, it will not be found.
Exercises Section 18.2.3
Exercise 18.18
Given the following typical definition of swap(13.3), determine which version of swap is used if mem1 is a string. What if mem1 is an int? Explain how name lookup works in both cases.
void swap(T v1, T v2)
{
using std::swap;
swap(v1.mem1, v2.mem1);
// swap remaining members of type T
}
- By stating
using std::swap
, all the following uses of swap will look for the matching template for its argument types in the standard library.
std::swap(string, string);
std::swap(int, int);
Exercise 18.19
What if the call to swap was std::swap(v1.mem1, v2.mem1)?
- Same as before.
18.2.4. Overloading and Namespaces
- Namespaces have two impacts on function matching(6.4). One is obvious: A using declaration or directive can add functions to the candidate set.
Argument-Dependent Lookup and Overloading
- The rule(Name lookup for functions that have class-type arguments includes the namespace in which each arguments class is defined) impacts how we determine the candidate set.
- Each namespace that defines a class used as an argument and those that define its base classes 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 are not visible at the point of the call.
namespace NS
{
class Quote { /* ... */ };
void display(const Quote&) { /* ... */ }
}
// Bulk_item's base class is declared in namespace NS
class Bulk_item : public NS::Quote { /* ... */ };
int main()
{
Bulk_item book1;
display(book1);
return 0;
}
- The argument we passed to display has class type Bulk_item. The candidate functions for the call to display are not only the functions with declarations that are in scope where display is called, but also the functions in the namespace where Bulk_item and its base class, Quote, are declared.
The functiondisplay(const Quote&)
declared in namespace NS is added to the set of candidate functions.
Overloading and using Declarations
- A using declaration declares a name, not a specific function(15.6).
using NS::print(int);
// error: cannot specify a parameter list
using NS::print;
// ok: using declarations specify names only
- When we write a using declaration for a function, all the versions of that function are brought into the current scope.
- 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 appears in a local scope, these names hide existing declarations for that name in the outer scope.
- 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 lib_R_us
{
extern void print(int);
extern void print(double);
}
// ordinary declaration
void print(const std::string &);
// this using directive adds names to the candidate set for calls to print:
using namespace lib_R_us;
// the candidates for calls to print at this point in the program are:
// print(int) from lib_R_us
// print(double) from lib_R_us
// print(const std::string &) declared explicitly
void fooBar(int ival)
{
print("Value: ");
// calls global print(const string &)
print(ival);
// calls lib_R_us::print(int)
}
- Different from using declarations, it is not an error if a using directive introduces a function that has the same parameters as an existing function. There is no problem unless we try to call the function without specifying whether we want the one from the namespace or from the current scope.
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 create 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)
, andprint(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 18.2.4
Exercise 18.20
In the following code, determine which function, if any, matches the call to compute. List the candidate and viable functions. What type conversions, if any, are 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);
void f()
{
compute(0);
}
What would happen if the using declaration were located in main before the call to compute? Answer the same questions as before.
- Useless.
Please indicate the source: http://blog.csdn.net/gaoxiangnumber1
Welcome to my github: https://github.com/gaoxiangnumber1
最后
以上就是热情心锁为你收集整理的18.2-Namespaces的全部内容,希望文章能够帮你解决18.2-Namespaces所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复