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

Указатели на функцию

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

  • Указатели и ссылки на определенный вид функций;

  • Указатели и ссылки на статические данные;

  • Указатели на «чистые» элементы: функции-класса;

  • Указатели на «чистые» элементы: переменные класса;

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

template <class R, class F, F f, class G, G g> // Объявляем в списке параметров шаблона

struct compose_fg2

{

typedef R result_type;

template <class T>

R operator()(T const& x) const

{

return f(g(x));

}

};

Несмотря на то, что шаблон не содержит вложенных элементов, элементы из списка параметров могут использоваться в его теле, например для следующего расчета (sin2(log2(x))), который применяется к каждому элементу последовательности:

#include <functional>

#include <algorithm>

#include <cmath>

float input[5] = {0.0, 0.1, 0.2, 0.3, 0.4};

float output[5];

inline float log2(float x) { return std::log(x)/std::log(2); }

typedef float (*floatfun)(float);

float* ignored = std::transform(

input, input+5, output,

compose_fg2<float, floatfun, sin_squared, floatfun, log2>()

);

Дополнительный уровень косвенности посредством указателей, на большинстве компиляторов, не будет приводить к снижению эффективности вызовов, т.к. компилятор точно знает на какие функции ссылаются указатели f и g, в результате компилятор должен оптимизировать пустой объект compose_fg2, передаваемый в std::transform и осуществить прямые вызовы log2 и sin_squared.

Несмотря на все свои преимущества эффективности, compose_fg2 имеет ряд ограничений:

  • Поскольку значения тип класса не могут выступать в качестве значений шаблонных параметров, compose_fg2 не может принимать в качестве аргументов функторы.

  • Нет способа создавать объект посредством функции-генератора для автоматического вывода параметров шаблона compose_fg2. Объект генератор придется взять на себя функции, будет состоять в качестве аргументов функции и использовать эти значения в качестве аргументов compose_fg2 шаблон:

template <class R, class F, class G>

// Ошибка: не может определить тип возвращаемого значения из-за f и g.

compose_fg2<R,F,f,G,g> compose(F f, G g)

{

return compose_fg2<R,F,f,G,g>(); // error

}

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

Ослабление типизации

Иногда полезно иметь возможность обходить статическую информацию о типе.

Например:

compose<float>(std::negate<float>(), &sin_squared)

с типом:

compose_fg<float,std::negate<float>,float(*)(float)>

std::bind2nd(std::multiplies<float>(), 3.14159)

с типом:

std::binder2nd<std::multiplies<float>>

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

std::transform(

input, input+5, output,

compose<float>(std::negate<float>(), &sin_squared)

);

std::transform(

input, input+5, output,

std::bind2nd(std::multiplies<float>(), 3.14159)

);

Шаблонная функция не всегда являются лучшими обработчиками полиморфного поведения, особенно в следующих ситуациях:

  • Системы, структура которых может изменяться динамически (GUI) – требуют выполнения диспетчеризации на этапе выполнения.

  • Шаблонные функции не могут быть скомпилированы в объектный код и поставлены в библиотеках.

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

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