Поступать подобным образом не рекомендуется, но, возможно, совсем не по тем причинам, о которых вы подумали. Вас не удивляет, что этот фрагмент вообще компилируется? Многие программисты обращают внимание на то, что в приведенном фрагменте специализируется не обычный шаблон, а шаблон из пространства имен std. «Разве пространство std не должно быть местом священным, зарезервированным для разработчиков библиотек и недоступным для простых программистов? — спрашивают они. — Разве компилятор не должен отвергнуть любое вмешательство в творения бессмертных гуру С++?»
Вообще говоря, попытки модификации компонентов std действительно запрещены, поскольку их последствия могут оказаться непредсказуемыми, но в некоторых ситуациях минимальные изменения все же разрешены. А именно, программистам разрешается специализировать шаблоны std для пользовательских типов. Почти всегда существуют альтернативные решения, но в отдельных случаях такой подход вполне разумен. Например, разработчики классов умных указателей часто хотят, чтобы их классы при сортировке вели себя как встроенные указатели, поэтому специализация std:: less для типов умных указателей встречается не так уж редко. Далее приведен фрагмент класса shared_ptr из библиотеки Boost, упоминающегося в советах 7 и 50:
namespace std{
template
struct less
public // (boost - пространство имен)
binary_function
boost::shared_ptr
bool>{// в совете 40
bool operator() (const boost::shared_ptr
const boost::shared_ptr
{
return less
} // встроенный указатель
};//из объекта shared_ptr
}
В данном примере специализация выглядит вполне разумно, поскольку специализация less всего лишь гарантирует, что порядок сортировки умных указателей будет совпадать с порядком сортировки их встроенных аналогов. К сожалению, наша специализация less для класса Widget преподносит неприятный сюрприз.
Программисты С++ часто опираются на предположения. Например, они предполагают, что копирующие конструкторы действительно копируют,(как показано в совете 8, невыполнение этого правила приводит к удивительным последствиям). Они предполагают, что в результате взятия адреса объекта вы получаете указатель на этот объект (в совете 18 рассказано, что может произойти в противном случае). Они предполагают, что адаптеры bind1st и not2 могут применяться к объектам функций (см. совет 40). Они предполагают, что оператор + выполняет сложение (кроме объектов string, но знак «+» традиционно используется для выполнения конкатенации строк), что оператор - вычитает, а оператор == проверяет равенство. И еще они предполагают, что функция less эквивалентна operator<
В действительности operator< представляет собой нечто большее, чем реализацию less по умолчанию — он соответствует
В STL нет ни одного случая использования less, когда программисту бы не предоставлялась возможность задать другой критерий сравнения. Вернемся к исходному примеру с контейнером multiset
struct MaxSpeedCompare:
public binary_function
bool operator()(const Widget& Ihs.const Widget& rhs) const
{
return lhs,maxSpeed()
}
};
При создании контейнера multiset достаточно указать тип сравнения MaxSpeedCompare, тем самым переопределяя тип сравнения по умолчанию (less
multiset
Смысл этой команды абсолютно очевиден: мы создаем контейнер multiset с элементами Widget, упорядоченными в соответствии с классом функтора MaxSpeedCompare. Сравните со следующим объявлением:
multiset