Объекты функций STL. Функциональные адаптеры для функций классов

   
На этом шаге мы рассмотрим использование функциональных адаптеров для функций классов.

   
В стандартную библиотеку C++ включены дополнительные адаптеры, позволяющие вызвать некоторую функцию класса для
каждого элемента коллекции (таблица 1).

Таблица 1. Функциональные адаптеры для функций классов

ВыражениеОписание
mem_fun_ref(op)Вызов ор() как функции объекта
mem_fun (op)Вызов ор() как функции указателя на объект

   
В следующем примере адаптер mem_fun_ref вызывает функцию print() каждого элемента вектора:

class Person {
  private:
    std::string name;
  public:
    ...
    void print () const {
        std::cout << name << std::endl;
    }
    void printWithPrefix (std::string prefix) const {
        std::cout << prefix << name << std::endl;
    }
};

void foo (const std::vector<Person>& coll)
{
    using std::for_each;
    using std::bind2nd;
    using std::mem_fun_ref;

    // Вызов функции print() для каждого элемента вектора
    for_each (coll.begin(), coll.end(),
              mem_fun_ref(&Person::print));

    // Вызов функции printWithPrefix() для каждого элемента
    // - строка "person: " передается при вызове
    for_each (coll.begin(), coll.end(),
              bind2nd(mem_fun_ref(&Person::printWithPrefix),
                      "person: "));
}

int main()
{
    std::vector<Person> coll(5);
    foo(coll);

    std::vector<Person*> coll2;
    coll2.push_back(new Person);
    ptrfoo(coll2);
}

   
В функции foo() для каждого элемента вектора coll вызываются две функции класса Person: '

  • функция Person::print() вызывается без аргументов;
  • функции printWithPrefix() при вызове передается аргумент.

   
Чтобы вызвать функцию Person::print(), мы передаем объект функции mem_fun_ref(&Person::print) алгоритму for_each():

    for_each (coll.begin(), coll.end(),
              mem_fun_ref(&Person::print));

   
Адаптер mem_fun_ref трансформирует обращение к элементу в вызов указанной функции класса.

   
Почему необходимо использовать адаптер? Потому что алгоритму нельзя напрямую передать функцию класса. Если попытаться это
сделать, произойдет ошибка компиляции:

    for_each (coll.begin(), coll.end(),
              &Person::print);  // ОШИБКА: невозможно вызвать оператор () 
                                // для указателя на функцию класса

   
Проблема заключается в том, что for_each() вызывает оператор () для указателя, переданного в третьем аргументе, вместо
функции класса, на которую он ссылается. Адаптер mem_fun_ref решает эту проблему, преобразуя вызов оператора ().

   
Как показывает второй вызов for_each(), адаптер bind2nd также позволяет передать один аргумент вызванной
функции класса:

    for_each (coll.begin(), coll.end(),
              bind2nd(mem_fun_ref(&Person::printWithPrefix),
                      "person: "));

   
Наверное, вас удивляет, что адаптер называется mem_fun_ref, а не просто mem_fun. Исторически сложилось так, что первой
появилась другая версия функциональных адаптеров, которой и было присвоено название mem_fun. Адаптеры mem_fun
предназначались для последовательностей, содержащих указатели на элементы. Возможно, во избежание путаницы их следовало бы
назвать mem_ fun_ptr. Следовательно, функции классов могут вызываться не только для серий объектов, но и для серий
указателей на объекты. Пример:

void ptrfoo (const std::vector<Person*>& coll)
                                   // ^^^ указатель!
{
    using std::for_each;
    using std::bind2nd;
    using std::mem_fun;

    // Вызов функции print() для каждого объекта,
    // на который ссылается указатель
    for_each (coll.begin(), coll.end(),
              mem_fun(&Person::print));
    // Вызов функции printWithPrefix () для каждого объекта,
    // на который ссылается указатель
    // - строка "person: " передается при вызове
    for_each (coll.begin(), coll.end(),
              bind2nd(mem_fun(&Person::printWithPrefix),
                      "person: "));
}

   
Адаптеры mem_fun_ref и mem_fun позволяют вызывать функции классов без аргументов или с одним аргументом.
Вызвать функцию с двумя аргументами подобным образом не удастся. Дело в том, что для реализации этих адаптеров необходимы
вспомогательные объекты функций, предоставляемые для каждого вида функций. Например, вспомогательные классы для
mem_fun и mem_fun_ref называются mem_fun_t, mem_fun_ref_t, const_mem_fun_t, const_mem_fun_ref_t,
mem_ funl_t, mem_funl_ref_t, const_mem_funl_t и const_mem_funl_ref_t.

   
Учтите, что функции классов, вызываемые mem_fun_ref и mem_fun, должны быть константными. К сожалению,
стандартная библиотека C++ не предоставляет функциональных адаптеров для неконстантных функций классов.

   
На следующем шаге мы рассмотрим функциональные адаптеры для обычных функций.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

Оставить комментарий