Вход/Регистрация
Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ
вернуться

Майерс Скотт

Шрифт:

...

void swap(Widget& other)

{

using std::swap; // необходимость в этом объявлении

// объясняется далее

swap(pimpl, other.pimpl); // чтобы обменять значениями два объекта

} // Widget,обмениваем указатели pimpl

...

};

namespace std {

template <> // переделанная версия

void swap<Widget>(Widget& a, // std::swap

Widget& b)

{

a.swap(b); // чтобы обменять значениями Widget,

} // вызываем функцию-член swap

}

Этот вариант не только компилируется, но и полностью согласован с STL-контейнерами, каждый из которых предоставляет и открытую функцию-член swap, и специализированную версию std::swap, которая вызывает эту функцию-член.

Предположим, однако, что Widget и Widgetlmpl – это не обычные, а шаблонные классы. Возможно, это понадобилось для того, чтобы можно было параметризировать тип данных, хранимых в Widgetlmpl:

template <typename T>

class WidgetImpl {...};

template <typename T>

class Widget {...};

Поместить функцию-член swap в Widget (и при необходимости в Widgetlmpl) в этом случае так же легко, как и раньше, но мы сталкиваемся с проблемой, касающейся специализации std::swap. Вот что мы хотим написать:

namespace std {

template <typename T>

void swap<Widget<T>>(Widget<T>& a, // ошибка! Недопустимый код

Widget<T>& b)

{ a.swap(b);}

}

Выглядит совершенно разумно, но все равно неправильно. Мы пытаемся частично специализировать шаблон функции (std::swap), но, хотя C++ допускает частичную специализацию шаблонов класса, он не разрешает этого для шаблонов функций. Этот код не должен компилироваться (если только некоторые компиляторы не пропустят его по ошибке).

Когда вам нужно «частично специализировать» шаблон функции, лучше просто добавить перегруженную версию. Примерно так:

namespace std {

template <typename T>

void swap(Widget<T>& a, // перегрузка std::swap

Widget<T>& b) // (отметим отсутствие <...> после

{ a.swap(b);} // “swap”), далее объяснено, почему

} // этот код некорректен

Вообще, перегрузка шаблонных функций – нормальное решение, но std – это специальное пространство имен, и правила, которым оно подчиняется, тоже специальные. Можно полностью специализировать шаблоны в std, но нельзя добавлять в std новые шаблоны (или классы, или функции, или что-либо еще). Содержимое std определяется исключительно комитетом по стандартизации C++, и нам запрещено пополнять список того, что они решили включить туда. К сожалению, форма этого запрета может привести вас в смятение. Программы, которые нарушают его, почти всегда компилируются и исполняются, но их поведение не определено! Если вы не хотите, чтобы ваши программы вели себя непредсказуемым образом, то не должны добавлять ничего в std.

Что же делать? Нам по-прежнему нужен способ, чтобы разрешить другим людям вызывать swap и иметь более эффективную шаблонную версию. Ответ прост. Мы, как и раньше, объявляем свободную функцию swap, которая вызывает функцию-член swap, но не говорим, что это специализация или перегруженный вариант std::swap. Например, если вся функциональность, касающаяся Widget, находится в пространстве имен WidgetStuff, то это будет выглядеть так:

namespace WidgetStuff {

... // шаблонный WidgetImpl и т. п.

template<typename T> // как и раньше, включая

class Widget {...}; // функцию-член swap

...

template<typename T> // свободная функция swap

void swap(Widget<T>& a, // не входит в пространство имен std

Widget<T>& b)

{

a.swap(b);

}

}

Теперь если кто-то вызовет swap для двух объектов Widget, то согласно правилам поиска имен в C++ (а точнее, согласно правилу учета зависимостей от аргументов) будет найдена специфичная для Widget версия в пространстве имен WidgetStuff. А это как раз то, что мы хотим.

  • Читать дальше
  • 1
  • ...
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

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

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: