Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
template_metaprogramming_ru.docx
Скачиваний:
12
Добавлен:
01.07.2025
Размер:
774 Кб
Скачать
☆

Автоматизация

С помощью шаблонов можно обобщить процесс введения новый реализаций настроек:

class screensaver

{

private:

struct customization

{

virtual ~customization() {}

virtual float operator()(float) const = 0;

};

template <class F> // a wrapper for an F

struct wrapper : customization

{

explicit wrapper(F f)

: f(f) {} // store an F

float operator()(float x) const

{

return this->f(x); // delegate to stored F

}

private:

F f;

};

public:

template <class F>

explicit screensaver(F const& f)

: get_seed(new wrapper<F>(f))

{}

//...

private:

std::auto_ptr<customization> get_seed;

//...

};

Теперь можно передавать любые указатели на функции или функторы в конструктор класса screensaver, до тех пор, пока аргументом вызова и результатом выступает тип float.

Сохранение интерфейса

При таком подходе процесс ослабления типовой информации является результатом превращения разнообразных типов с общим интерфейсом в один тип, конкретизируя данный интерфейс. Так, конкретная реализация сохранялась в auto_ptr <customization>, который является элементом класса screensaver. Сам auto_ptr не вызываемый, в только хранящися в нем указатель и сам вызов мог бы быть расположен в теле данного класса. Лучши решением будет вынести данную обертку за пределы тела класса и организовать ее отдельным классом float_function, чтобы позволит использовать ее в любом проекте.

Сам класс «заставки» избавляется от деталей реализации и становится более выразительным:

class screensaver

{

public:

explicit screensaver(float_function f)

: get_seed(f)

{}

pixel_map next_screen()

{

float center_pixel_brightness = ...;

float seed = this->get_seed(center_pixel_brightness);

//...

}

private:

float_function get_seed;

//...

};

Рефакторинга позволяет реализовать для общего интерфейса всех функторов возможность создания копий. Чтобы сделать возможным копирование и хранение объектов класса float_function в теле класса screensaver необходимо применить, рассмотренные выше, механизмы виртуализации и создания оболочек для реализаций, для использования их при копировании объектов.

Виртуализация позволит создавать множество реализаций единого интерфейса настроек.

Оболочка для типов – обобщенный вариант реализации интерфейса и клонирования, которая наследует данный интерфейс и позволяет хранить указатели на функции или функторы.

Механизм клонирования будет использован в конструкторе копии.

class float_function

{

private:

// Абстрактный интерфейс для настроек класса screensaver.

struct impl

{

virtual ~impl() {}

virtual impl* clone() const = 0;

virtual float operator()(float) const = 0;

};

// Обобщенный вариант реализации и клонирования:

template <class F>

struct wrapper : impl

{

explicit wrapper(F const& f) : f(f) {}

impl* clone() const

{

return new wrapper<F>(this->f); // delegate

}

float operator()(float x) const

{

return f(x); // delegate

}

private:

F f;

};

public:

// Конструктор-преобразования позволит инициализировать состояние

// переданным типом.

template <class F>

float_function(F const& f) : pimpl(new wrapper<F>(f)) {}

// Конструктор-копии использует элементы оболочки.

float_function(float_function const& rhs)

: pimpl(rhs.pimpl->clone()){}

float_function& operator=(float_function const& rhs)

{

this->pimpl.reset(rhs.pimpl->clone()); // создаем клона и меняем состояние.

return *this;

}

float operator()(float x) const

{

return (*this->pimpl)(x);

}

private:

std::auto_ptr<impl> pimpl;

};

Данный класс позволяет «захватывать» функциональность любой вызываемой сущности, которая принимает и возвращает тип float. Это основной паттерн библиотеки Boost Function Library, представленный в TR1, где его обобщенная версия поддерживать произвольные аргументы и возвращаемые типы. Так, вся реализация float_function может быть заменена на вариант из Boost следующим образом:

typedef boost::function<float (float x)> float_function;

Аргументом шаблона является тип функции, которым будет специфицирован отдельный функтор.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]