Private-Bookers
C++. Сборник рецептов
вернуться

Когсуэлл Джефф

Шрифт:

 explicit comma_helper(Seq_T& x) : m(x) {}

 comma_helper& operator=(const value_type& x) {

m.clear;

return operator+=(x);

 }

 comma_helper& operator+=(const value_type& x) {

m.push_back(x);

return *this;

 }

 Seq_T& m;

};

template<typename Seq_T>

comma_helper<Seq_T> initialize(Seq_T& x) {

 return comma_helper<Seq_T>(x);

}

template<class Seq_T, class Scalar_T>

comma_helper<Seq_T>& operator,(comma_helper<Seq_T>& h, Scalar_T x) {

 h += x;

 return h;

}

int main {

 vector v;

 int a = 2;

 int b = 5;

 initialize(v) = 0, 1, 1, a, 3, b, 8, 13;

 cout << v[3] << endl; // выдает 2

 system("pause");

 return EXIT_SUCCESS;

}

Обсуждение

Часто стандартные последовательности инициализируются путем вызова несколько раз функции-члена

push_back
. Поскольку это приходится делать не так уж редко, я написал функцию
initialize
, которая помогает избавиться от этого скучного занятия, позволяя выполнять инициализацию значениями, разделяемыми запятыми, подобно тому как это делается во встроенных массивах.

Возможно, вы и не знали, что запятая является оператором, который можно переопределять. Здесь вы не одиноки — этот факт не является общеизвестным. Оператор запятой было разрешено перегружать почти только ради решения этой задачи.

В решении используется вспомогательная функция

initialize
, которая возвращает шаблон вспомогательной функции
comma_helper
. Этот шаблон содержит ссылку на последовательность и перегруженные операторы
operator,
,
operator=
и
operator+=
.

Такое решение требует, чтобы я определил отдельную вспомогательную функцию из-за особенностей восприятия компилятором оператора

v = 1, 1, 2, ...;
. Компилятор рассматривает
v = 1
как недопустимое подвыражение, потому что в стандартных последовательностях не поддерживается оператор присваивания единственного значения. Функция
initialize
конструирует соответствующий объект
comma_helper
, который может хранить последовательность, используемую в перегруженном операторе присваивания и запятой.

Оператор запятой (comma operator), называемый также оператором последовательности (sequencing operator), по умолчанию рассматривает выражения слева направо, и в результате получается значение и тип самого правого значения. Однако при перегрузке

operator
принимает новый смысл и теряет первоначальную семантику. Здесь возникает один тонкий момент — оценка параметров слева направо теперь не гарантируется, и результат выполнения программного кода, приведенного в примере 15.7, может оказаться неожиданным.

Пример 15.7. Применение перегруженного оператора запятой, когда порядок вычисления аргументов не определен

int prompt_user {

 cout << "give me an integer ... ";

 cin >> n;

 return n;

}

void f {

 vector<int> v;

 // Следующий оператор может инициализировать v в неправильной

 // последовательности

 intialize(v) = prompt_user, prompt_user;

}

В правильном варианте функции

f
каждый вызов
prompt_user
должен был бы выполняться в отдельном операторе.

Библиотека Boost Assign, написанная Торстеном Оттосеном (Thorsten Ottosen), кроме других форм инициализации стандартных коллекций поддерживает также более сложную форму инициализации списком с запятыми. Эта библиотека доступна на сайте http://www.boost.org.

  • Читать дальше
  • 1
  • ...
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270

Private-Bookers - русскоязычная библиотека для чтения онлайн. Здесь удобно открывать книги с телефона и ПК, возвращаться к сохраненной странице и держать любимые произведения под рукой. Материалы добавляются пользователями; если считаете, что ваши права нарушены, воспользуйтесь формой обратной связи.

Полезные ссылки

  • Моя полка