C++ 3d.Комментарии

       

Вызов функции


Функция, которая вызывается повторно, -- это operator()() объекта Add(z).

Использование шаблонов и смысл их параметров может стать для вас совершенно непонятным, если раз и навсегда не уяснить одну простую вещь: при вызове функции-шаблона вы передаете объекты, но критически важной для инстанциирования шаблонов информацией являются типы переданных объектов. Сейчас я проиллюстрирую данную идею на приведенном в книге примере.

Рассмотрим, например, определение функции-шаблона for_each()

template <class InputIter, class Function> Function for_each(InputIter first, InputIter last, Function f) { for ( ; first != last; ++first) f(*first); return f; }

Данное определение я взял непосредственно из sgi STL (предварительно убрав символы подчеркивания для улучшения читаемости). Если сравнить его с приведенным в книге, то сразу бросается в глаза исправление типа возвращаемого значения (по стандарту должен быть аргумент-функция) и отказ от использования потенциально менее эффективного постинкремента итератора.

Когда мы вызываем for_each() c аргументом Add(z), for_each(ll.begin(), ll.end(), Add(z));

то Function -- это Add, т.е. тип, а не объект Add(z). И по определению for_each() компилятором будет сгенерирован следующий код: Add for_each(InputIter first, InputIter last, Add f) { for ( ; first != last; ++first) f.operator()(*first); return f; }

Т.о. в момент вызова for_each() будет создан временный объект Add(z), который затем и будет передан в качестве аргумента. После чего, внутри for_each() для копии этого объекта будет вызываться Add::operator()(complex&). Конечно, тип InputIter также будет заменен типом соответствующего итератора, но в данный момент это нас не интересует.

На что же я хочу обратить ваше внимание? Я хочу отметить, что шаблон -- это не макрос в который передается что-то, к чему можно приписать скобки с соответствующими аргументами. Если бы шаблон был макросом, непосредственно принимающим переданный объект, то мы бы получили Add for_each(...) { for (...) Add(z).operator()(*first); return f; }

что, в принципе, тоже корректно, только крайне неэффективно: при каждом проходе цикла создается временный объект, к которому затем применяется операция вызова функции.



Содержание раздела