Программирование >>  Обобщенные обратные вызовы 

1 ... 5 6 7 [ 8 ] 9 10 11 ... 84


std::vector<Employee*> emp ptrs;

std::for each(emp ptrs.begi n(), emp ptrs.end(),

std::mem fun(&Employee::DoStandardRai se));

Вы, вероятно, обратили внимание, что для ясности я воспользовался функцией без параметров. Вы можете воспользоваться вспомогательными классами bind... для функций с аргументом --- принцип при этом остается тот же. К сожалению, вы не можете использовать этот подход для функций с двумя и более параметрами.

Вот, по сути, главное, что надо знать о mem fun. И это подводит нас к трудной части задачи.

Используйте mem fun, но не со стандартной библиотекой

2. Полагая, что в комментарии в приведенном коде все правильно, ответьте на вопрос: является ли приведенный код корректным и переносимым кодом С++? Обоснуйте свой ответ.

std::mem fun</*...*/>( &std::vector<int>::clear )

Я специально сформулировал вопрос таким образом (с комментарием вместо аргумента шаблона), поскольку некоторые распространенные компиляторы в такой ситуации не в состоянии корректно вывести аргументы шаблона. Для них, в зависимости от ва1исй реализации стандартной библиотеки, может потребоваться написать что-то наподобие

std: :mem fun<void, std: :vector<int, std::anocator<int> > > ( &std::vector<int>::clear);

Co временем это ограничение должно бьггь ликвидировано, и компиляторы будут позволять опускать параметры шаблонов.

Вы можете удивиться моим примечанием в зависимости от вашей реализации стандартной библиотеки . В конце концов, сигнатура std: : vector<i ni>: : clear гласит, что эта функция не получает параметров и ничего не возвращает, ведь так? Разве стандарт не говорит нам об этом?

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

Спецификация стандартной библиотеки coзнaтeль[o предоставляет разработчикам определенную свободу действий по реализации функций-членов. В частности:

СИ1 натура функции-члена с параметрами по умолчанию может бьпъ заменена двумя или более сигнатурами функций-членов с эквивалентным поведением ;

сигнатура функции-члена может иметь дополнительные параметры по умолчанию.

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

В большинстве случаев в этом нет никаких проблем, и все эти параметры по умолчанию просто остаются незамеченными. Например, при вызове функции-члена эти скрытые параметры, которых вы не передаете, попадают в функцию в виде значений по умолчанию, и вы даже не подозреваете об их существовании. Но, к сожалению, эти параметры начинают играть важную роль, когда ста1ювится важна точная сигнатура функции......... например, когда вы пытаетесь использовать mem fun, За.метим, что

это происходит, даже если ваш компилятор корректно выводит аргументы шаблонов. Это связано с двумя потенциальными проблема.ми.

Если рассматриваемая функция-член полушет параметр, о котором вы не подозревали, вам понадобится написать что-то наподобие std:; bi nd2nd дня того, чтобы избавиться от него (более подробное описание использования стандартных замыканий параметров функции можно найти в [Josuttis99j)- Конечно, после этого ваш код не будет работать в реализации, где используется дополнительный



параметр другого типа или этого параметра нет вовсе, но в конце концов ваш код и без этого все равно не был бы переносимым, правда?

Если функция-член в действительности имеет два или больше параметров (даже если они имеют значения по умолчанию), вы вообще не сможете воспользоваться mem fun.

На практике, впрочем, все может быть не настолько плохо. Пока что мне пе BCTpenajmcb реализации, где разработчики широко пользовались бы своим правом на свободу действий по добавлению дополнительных параметров, либо намеренных воспользоваться им в будущем. И пока это так, вы не заметите проблем с этим кодом.

Увы, на этом наша история не заканчивается. Давайте рассмотрим более обшее следствие такой свободы действий.

Использование указателей на функции-члены - но не со стандартной библиотекой

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

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

Резюме

Достаточно странно, что вы можете переносимо использовать возможность стандартной библиотеки (а именно - mem fun) практически с любым кодом, кроме хода самой стандартной библиотеки. Не менее странно, что можно переносимо использовать возможность языка (а именно - указатели на функции-члены) со всеми функциями-членами, .за исключением таковых в стандартной библиотеке этого языка.

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



Задача 5. Красота обобщенности.

Часть 1: Азы Сложность: 4

Перед тем как приступить к шестой задаче, рассмотрим простой пример гибкого обобщенного кода С++ (примеры кода в этой и следующей задаче взяты из [SutterOOj.

Вопрос для новичка

1. Шаблоны С++ обеспечивают полиморфизм времени компиляции . Поясните эту фразу.

Вопрос для профессионала

2. Поясните семантику приведенной функции. Дайте максимально полный ответ и обязательно поясните, почему в ней использованы два парамефа шаблона, а не один.

template <с1ass т1, class Т2> void constructC т1* р, const т2& value ) { new (р) Tl(value);

Решение

1. Шаблоны С++ обеспечивают полиморфизм времени компиляции . Поясните эту фразу.

Когда мы говорим о полиморфизме в объектно-ориентированном мире, мы подразумеваем полиморфизм времени выполнения, который основан на использовании виртуальных функций. Базовый класс определяет интерфейс, представляющий собой набор виртуальных функций, а производные классы мог)т наследовать их из базового класса и перекрывать их таким образом, чтобы сохранялась предполагаемая интерфейсом семантика. Тогда код, который работает с базовым объектом (получая объект Base через указатель или по ссылке), может точно так же работать и с объектом производного класса.

пример 5~1(а): полиморфизм времени выполнения.

class Base { public:

vi rtual voi d f () ;

virtual void g Q ;

class Derived : public Base {

перекрытие при необходимости f и/или g

void h( Base& b ) { b.fO; b.gO;

int mai n() { Derived d; h( d );

Это очень важная возможность, обеспечивающая высокую степень гибкости времени выполнения. Однако полиморфизм времени выполнения имеет и два существенных недостатка, Во-псрвььх, типы должны быть иерархически связаны отношением



1 ... 5 6 7 [ 8 ] 9 10 11 ... 84

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика