компилируется, а следующие конструкции не компилируются:
for_each(vw.begin().vw.end(),&Widget::test); //См. ранее, вариант 2.
// Не компилируется.
for_each(lpw.begin(),lpw.end(), &Widget::test): //См. ранее, вариант 3.
//Не компилируется
При первом вызове (вариант 1) передается настоящая функция, поэтому адаптация синтаксиса вызова для for_each не нужна; алгоритм сам вызовет ее с правильным синтаксисом. Более того, foreach не использует определения типов, добавляемые функцией ptr_fun, поэтому при передаче test функция ptr_fun не нужна. С другой стороны, добавленные определения не повредят, поэтому следующий фрагмент функционально эквивалентен приведенному выше:
for_each(vw.begin(),vw.end().ptr_fun(test)): // Компилируется и работает.
// как вариант 1.
Если вы забываете, когда функция ptr_fun обязательна, а в каких случаях без нее можно обойтись, лучше используйте ее при всех передачах функций компонентам STL. STL игнорирует лишние вызовы, и они не отражаются на быстродействии программы. Возможно, во время чтения вашей программы кто-нибудь удивленно поднимет брови при виде лишнего вызова ptr_fun. Насколько это беспокоит вас? Наверное, ответ зависит от природной мнительности.
Существует и другой подход — использовать ptr_fun в случае крайней необходимости. Если функция отсутствует там, где необходимы определения типов, компилятор выдает сообщение об ошибке. Тогда вы возвращаетесь к программе и включаете в нее пропущенный вызов.
С mem_fun и mem_fun_ref ситуация принципиально иная. Эти функции всегда должны применяться при передаче функции компонентам STL, поскольку помимо определения типов (необходимых или нет) они адаптируют синтаксис вызова, который обычно используется для функций класса, к синтаксису, принятому в STL. Если не использовать эти функции при передаче указателей на функции класса, программа не будет компилироваться.
Остается лишь разобраться со странными именами адаптеров. Перед нами самый настоящий пережиток прошлого STL. Когда впервые возникла необходимость в адаптерах, разработчики STL ориентировались на контейнеры указателей (с учетом недостатков таких контейнеров, описанных в советах 7,20 и 33, это может показаться странным, но не стоит забывать, что контейнеры указателей поддерживают полиморфизм, а контейнеры объектов — нет). Когда понадобился адаптер для функций классов (MEMber FUNctions), его назвали mem_fun. Только позднее разработчики поняли, что для контейнеров объектов понадобится другой адаптер, и для этой цели изобрели имя mem_fun_ref. Конечно, выглядит не слишком элегантно, но... бывает, ничего не поделаешь. Пусть тот, кому никогда не приходилось жалеть о поспешном выборе имен своих компонентов, первым бросит камень.
Совет 42. Следите за тем, чтобы конструкция less
Допустим, объект класса Widget обладает атрибутами weight и maxSpeed:
class Widget { public:
size_t weight() const;
size_t maxSpeed() const;
}
Будем считать, что естественная сортировка объектов Widget осуществляется по атрибуту weight, что отражено в операторе < класса Widget:
bool operator<(const Widget& Ihs. const Widget& rhs) {
return lhs.weight()
}
Предположим, потребовалось создать контейнер multiset
template<> // Специализация std::less
struct std::less
public // считается крайне нежелательным!
std::binаry_function
Widget,// Базовый класс описан
bool>{// в совете 40
bool operator() (const Widget& Ihs. const Widget& rhs) const
{
return lhs.maxSpeed()
}
};