Читаем Thinking In C++. Volume 2: Practical Programming полностью

For convenience we have included two emptyStack function templates. Since function templates don’t support partial specialization, we provide overloaded templates. The second version of emptyStack is more specialized than the first, so it is chosen whenever pointer types are used. Three class templates are instantiated in this program: Stack, Stack, and Stack. Stack is implicitly instantiated because Stack derives from it. If a program uses instantiations for many pointer types, the savings in code size over just using a single Stack template can be substantial.

<p>Name lookup issues</p>

When the compiler encounters an identifier it must determine the type and scope (and in the case of variables, the lifetime) of the entity the identifier represents. This is common knowledge among software developers, but the plot thickens when templates are involved. Because not everything is known about a template when its definition is first seen by the compiler, the compiler must hold off until the template is instantiated before it can determine whether it is being used properly. This predicament leads to a two-phase process for template compilation.

<p>Names in templates</p>

In the first phase the compiler parses the template definition looking for obvious syntax errors and resolving all the names it can. The names it can resolve during parsing are those that do not depend on template parameters, which the compiler takes care of through normal name lookup means (and also through argument-dependent lookup, discussed below, if necessary). The names it can’t resolve are the so-called dependent names, which are names that in some way depend on template parameters. These can’t be resolved until the template is instantiated with its actual arguments. Instantiation, therefore, is the second phase of template compilation. During this second phase, the compiler determines whether an explicit specialization of the template in question needs to be used instead of the primary template.

Before you see an example, two more terms need to be defined. A qualified name is a name with a class-name prefix, a name with an object name and a dot operator, or a name with a pointer to an object and an arrow operator. Examples of qualified names are found in the following expressions:.

MyClass::f();

x.f();

p->f();

We have used qualified names many times in this book, and most recently in connection with the typename keyword. These are called qualified names because the target names (like f above) are explicitly associated with a class, which tells the compiler where to look for the declarations of those names.

The other term to discuss is argument-dependent lookup[60] (ADL), which is a technique originally designed to simplify using non-member function calls (including operators) declared in namespaces. Consider the following simple code excerpt:.

#include

#include

//…

  std::string s("hello");

  std::cout << s << std::endl;

Note that there is no using namespace std; directive, which is the typical practice inside header files, for example. Without such a directive, it is necessary to use the std:: qualifier on the items that are in the std namespace. We have, however, not qualified everything from std that we are using. Can you see what we have left unqualified?.

We have not specified which operator functions to use. We want the following to happen, but we don’t want to have to type it!

std::operator<<(std::operator<<(std::cout,s),std::endl);

To make the original output statement work as desired, ADL specifies that when an unqualified function call appears and its declaration is not in (normal) scope, the namespaces (or class scopes) of each of its arguments are searched for a matching function declaration. In the original statement, the first function call is:.

operator<<(std::cout, s);

Since there is no such function in scope in our original excerpt, the compiler notes that this function’s first argument (std::cout) is in the namespace std; so it adds that namespace to the list of scopes to search for a unique function that best matches the signature operator<<(std::ostream&, std::string). It finds this function declared in the std namespace via the header, so that is the function that is called. Namespaces would be very inconvenient without ADL. (But note that, in general, ADL brings in all declarations of the name in question from all eligible namespaces—if there is no best match, an ambiguity will result.) To turn off ADL, you can enclose the function name in parentheses:.

(f)(x, y);  // ADL suppressed

Now consider the following program, from a presentation by Herb Sutter:

// Lookup.cpp

// Only works on EDG and Metrowerks (special option)

#include

using std::cout;

void f(double) { cout << "f(double)\n"; }

template

class X {

public:

  void g() { f(1); }

};

Перейти на страницу:

Похожие книги

3ds Max 2008
3ds Max 2008

Одни уверены, что нет лучшего способа обучения 3ds Мах, чем прочитать хорошую книгу. Другие склоняются к тому, что эффективнее учиться у преподавателя, который показывает, что и как нужно делать. Данное издание объединяет оба подхода. Его цель – сделать освоение 3ds Мах 2008 максимально быстрым и результативным. Часто после изучения книги у читателя возникают вопросы, почему не получился тот или иной пример. Видеокурс – это гарантия, что такие вопросы не возникнут: ведь автор не только рассказывает, но и показывает, как нужно работать в 3ds Мах.В отличие от большинства интерактивных курсов, где работа в 3ds Мах иллюстрируется на кубиках-шариках, данный видеокурс полностью практический. Все приемы работы с инструментами 3ds Мах 2008 показаны на конкретных примерах, благодаря чему после просмотра курса читатель сможет самостоятельно выполнять даже сложные проекты.

Владимир Антонович Верстак , Владимир Верстак

Программирование, программы, базы данных / Программное обеспечение / Книги по IT