Заголовок functional.hpp включает в себя улучшенные версии полного спектра адаптеров функций членов от C++. Стандартная библиотека (§20.3.8):
mem_fun_t
mem_fun1_t
const_mem_fun_t
const_mem_fun1_t
mem_fun_ref_t
mem_fun1_ref_t
const_mem_fun_ref_t
const_mem_fun1_ref_t
а также соответствующие перегруженные функции помощника
mem_fun
mem_fun_ref
В адаптеры были внесены следующие изменения, указанные в Стандарте:
first_argument_typetypedef был исправлен дляconst_семейства адаптеров функций членов (см.ниже).
Аргумент передаетсяmem_fun1_tи его варианты передаются с использованиемcall_traits::param_typeдля типа аргумента функции члена.
first_argument_type
Стандарт определяет const_mem_fun1_t, например:
template <class S, class T, class A> class const_mem_fun1_t
: public binary_function<T*, A, S> {
public:
explicit const_mem_fun1_t(S (T::*p)(A) const);
S operator()(const T* p, A x) const;
};
Обратите внимание, что первый аргумент binary_function является T*, несмотря на то, что первый аргумент operator() на самом деле имеет тип const T*.
Это имеет значение? Что происходит, когда мы пишем
Мы создали const_mem_fun1_t объект, который будет содержать следующие
typedef Foo* first_argument_type;
bind1st создает binder1st Объект, который будет использовать этот typedef в качестве типа элемента, который будет инициализирован с cp. Другими словами, нам нужно будет инициализировать элемент Foo* с указателем const Foo*! Очевидно, что это невозможно, поэтому для реализации этого стандартного библиотечного поставщика пришлось бы отбросить константу cp, вероятно, в теле bind1st.
Этого взлома будет недостаточно с улучшенными binders в этой библиотеке, поэтому нам пришлось предоставить исправленные версии адаптеров функций участников.
Argument Types
Стандарт определяет mem_fun1_t, например, как это (§20.3.8 ¶2):
template <class S, class T, class A> class mem_fun1_t
: public binary_function<T*, A, S> {
public:
explicit mem_fun1_t(S (T::*p)(A));
S operator()(T* p, A x) const;
};
Обратите внимание, что второй аргумент для оператора() является точно таким же, как и аргумент для функции члена. Если это тип стоимости, аргумент будет передан по стоимости и скопирован дважды.
Однако, если бы мы попытались устранить эту неэффективность, объявив аргумент const A&, то, если бы A был эталонным типом, у нас была бы ссылка на ссылку, которая в настоящее время является незаконной (но см. C++ основной язык номер 106)
Таким образом, способ, которым мы хотим объявить второй аргумент для оператора(), зависит от того, является ли аргумент функции-члена ссылкой. Если это ссылка, мы хотим объявить ее просто как A; если это значение, мы хотим объявить ее как const A&.
Шаблон класса Boost call_traits содержит тип param_type, который использует частичную специализацию для принятия именно этого решения. Объявив оператор()
S operator()(T* p, typename call_traits<A>::param_type x) const
мы достигаем желаемого результата – повышаем эффективность без создания ссылок на ссылки.
Limitations
Шаблон черт вызова, используемый для реализации некоторых улучшений, основан на частичной специализации, поэтому эти улучшения доступны только на компиляторах, которые поддерживают эту функцию. С другими компиляторами аргумент, переданный функции-члену (в семействе mem_fun1_t), всегда будет передаваться посредством ссылки, тем самым создавая возможность ссылок на ссылки.
Статья Boost Function Object Adapter Library раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.