Генерические библиотеки, которые принимают привлекательные аргументы, распространены в C++. Принятие вызывающего аргумента типа builin часто включает в себя много повторяющегося кода, потому что приемная функция перегружена для различных функций. Кроме того, функции-члены могут иметь const
/volatile
-qualifiers, функция может принимать переменное число (дополнительно, POD-типа) аргументов (например, printf
) и несколько реализаций C++ кодируют соглашение вызова с типом каждой функции, чтобы разрешить звонки через языковые или (подсистемные границы).
template<typename R>
void accept_function(R(* func)());
template<typename R>
void accept_function(R(& func)());
template<typename R, typename C>
void accept_function(R(C::* func)());
template<typename R, typename C>
void accept_function(R(C::* func)() const);
template<typename R, typename C>
void accept_function(R(C::* func)() volatile);
template<typename R, typename C>
void accept_function(R(C::* func)() const volatile);
template<typename R>
void accept_function(R(* func)(...));
template<typename R>
void accept_function(R(& func)(...));
template<typename R, typename C>
void accept_function(R(C::* func)(...));
template<typename R, typename C>
void accept_function(R(C::* func)(...) const);
template<typename R, typename C>
void accept_function(R(C::* func)(...) volatile);
template<typename R, typename C>
void accept_function(R(C::* func)(...) const volatile);
Очевидно, что «перегрузка подхода» не очень хорошо масштабируется: Может быть несколько функций, которые приемлемые аргументы в одной библиотеке и клиентском коде могут в конечном итоге использовать несколько библиотек, которые используют этот шаблон. На стороне разработчиков, разработчики библиотеки тратят свое время на решение одной и той же проблемы, работая над одними и теми же проблемами переносимости, и применяют аналогичные оптимизации, чтобы сократить время компиляции.
С помощью Boost. Функция Типы можно написать один шаблон функции вместо:
template<typename F>
void accept_function(F f)
{
}
Сочетание с библиотекой tuples, которая предоставляет компонент вызова, такой как Boost.Fusion, позволяет создавать гибкие резервные устройства, которые полностью свободны от повторяющегося кода, как показано на примере interpreter.
При приеме адреса перегруженной функции или шаблона функции тип функции должен быть известен из контекста, в котором используется выражение. Код ниже показывает три примера для выбора float(float)
перегрузка std::abs
.
float (*ptr_absf)(float) = & std::abs;
void foo(float(*func)(float));
void bar()
{
foo(& std::abs);
}
std::transform(b, e, o, static_cast<float(*)(float)>(& std::abs));
Возможности синтеза типа библиотеки могут быть использованы для автоматизации выбора перегрузки и моментирования шаблонов функций. Учитывая перегруженный шаблон функции
template<typename R, typename T0>
R overloaded(T0);
template<typename R, typename T0, typename T1>
R overloaded(T0,T1);
template<typename R. typename T0, typename T1, typename T2>
R overloaded(T0,T1,T2);
мы можем выбрать любую из трех перегрузок и мгновенный шаблон с аргументами шаблона из последовательности типа в одном выражении:
static_cast<function_pointer<Seq>::type>(& overloaded)
Этот метод может быть иногда более гибким, чем вывод аргументов шаблона из вызова функции, потому что точные типы из последовательности используются для специализации шаблона (включая, возможно, Cv-квалифицированные типы ссылок и тип результата). Он применяется дважды в примере интерфейса.
Другое взаимопереплетающее свойство коллируемых, встроенных типов заключается в том, что они могут быть действительными типами для нетиповых параметров шаблона. Таким образом, функция может быть назначена во время компиляции, что позволяет компилятору устранить вызов, делая акцент. fast_mem_fn example эксплуатирует эту характеристику и реализует потенциально намекающую версию boost::mem_fn, ограниченную функциями-членами, которые известны во время компиляции.