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

Both the definition of seq in Container and theData in main( ) use the default. The only way to use something other than the default value is as the previous program (TempTemp2.cpp) illustrated. This is the only exception to the rule stated earlier that default arguments should appear only once in a compilation unit.

Since the standard sequence containers (vector, list, and deque, discussed in depth in Chapter 7) have a default allocator argument, the technique shown above is helpful should you ever want to pass one of these sequences as a template parameter. The following program passes a vector and then a list to two instances of Container.

//: C05:TempTemp4.cpp

//{-bor}

//{-msc}

// Passes standard sequences as template arguments

#include

#include

#include   // Declares allocator

#include

using namespace std;

template >

     class Seq>

class Container {

  Seq seq; // Default of allocator applied implicitly

public:

  void push_back(const T& t) { seq.push_back(t); }

  typename Seq::iterator begin() { return seq.begin(); }

  typename Seq::iterator end() { return seq.end(); }

};

int main() {

  // Use a vector

  Container theData;

  theData.push_back(1);

  theData.push_back(2);

  for(vector::iterator p = theData.begin();

      p != theData.end(); ++p) {

    cout << *p << endl;

  }

  // Use a list

  Container theOtherData;

  theOtherData.push_back(3);

  theOtherData.push_back(4);

  for(list::iterator p2 = theOtherData.begin();

      p2 != theOtherData.end(); ++p2) {

    cout << *p2 << endl;

  }

} ///:~

In this case we name the first parameter of the inner template Seq (with the name U), because the allocators in the standard sequences must themselves be parameterized with the same type as the contained objects in the sequence. Also, since the default allocator parameter is known, we can omit it in the subsequent references to Seq, as we did in the previous program. To fully explain this example, however, we have to discuss the semantics of the typename keyword.

<p>The typename keyword</p>

Consider the following:.

//: C05:TypenamedID.cpp

//{-bor}

// Uses 'typename' as a prefix for nested types

template class X {

  // Without typename, you should get an error:

  typename T::id i;

public:

  void f() { i.g(); }

};

class Y {

public:

  class id {

  public:

    void g() {}

  };

};

int main() {

  X xy;

  xy.f();

} ///:~

The template definition assumes that the class T that you hand it must have a nested identifier of some kind called id. But id could also be a static data member of T, in which case you can perform operations on id directly, but you can’t "create an object" of "the type id.".

However, that’s exactly what is happening here: the identifier id is being treated as if it were actually a nested type inside T. In the case of class Y, id is in fact a nested type, but (without the typename keyword) the compiler can’t know that when it’s compiling X.

If the compiler has the option of treating an identifier as a type or as something other than a type when it sees an identifier in a template, it will assume that the identifier refers to something other than a type. That is, it will assume that the identifier refers to an object (including variables of primitive types), an enumeration, or something similar. However, it will not–cannot–just assume that it is a type.

Because the default behavior of the compiler is to assume that a name that fits the above two points is not a type, you must use typename for nested names (except in constructor initializer lists, where it is neither needed nor allowed). In the above example, when the compiler sees template T::id, it knows (because of the typename keyword) that id refers to a nested type and thus it can create an object of that type.

The short version of the rule is: if a type referred to inside template code is qualified by a template type parameter, it should be preceded by the typename keyword, unless it appears in a base class specification or initializer list in the same scope (in which case you must not).

All the above explains the use of the typename keyword in the program TempTemp4.cpp. Without it, the compiler would assume that the expression Seq::iterator is not a type, but we were using it to define the return type of the begin( ) and end( ) member functions.

The following example, which defines a function template that can print any standard C++ sequence, shows a similar use of typename.

//: C05:PrintSeq.cpp

//{-msc}

// A print function for standard C++ sequences

#include

#include

#include

#include

using namespace std;

template >

   class Seq>

void printSeq(Seq& seq) {

  for (typename Seq::iterator b = seq.begin();

       b != seq.end();)

    cout << *b++ << endl;

}

int main() {

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

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

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

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