Здравствуйте, Bell, Вы писали:
B>Здравствуйте, Amon-RA, Вы писали:
AR>>привет все. AR>>Люди, не объясните популярно, что такое функтор. Спасибо
B>Это объект класса, имеющего переопределенный оператор operator ()
Здравствуйте, Amon-RA, Вы писали:
AR>И зачем оно надо и зачем обзывать его по особенному?
А затем, чтобы заменить указатели на функции при обработке сложных структур данных.
С указателями, как ты понимаешь, хлопот больше, чем выгод.
А функтор — это ОБЪЕКТ, который можно передавать и по значению. Инкапсуляция и надежность программ повышаются.
А еще — можно состояния хранить — полей-то можно определить какие хочешь.
Если более подробно, то надо в книжках читать.
На эту тему много написано.
Хотя бы у Александреску.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Amon-RA, Вы писали:
AR>привет все. AR>Люди, не объясните популярно, что такое функтор. Спасибо
Функтор — собирательный термин, который обозначает все виды сущностей в С++, к которым применим оператор вызова функции — '()'. Функторы сразу делятся на два подкласса — 1) обыкновенные функции (указатели на обыкновенные функции) к которым применяется встроенный оператор '()' и 2) функциональные объекты — объекты классов с перегруженным оператором '()'.
Иногда под термином 'функтор' продразумевают только функциональные объекты. Это, строго говоря, некорректное употребление данного термина. Обычные функции и указатели на них тоже являются частными случаями функторов.
Best regards,
Андрей Тарасевич
Re[2]: Что такое функтор???
От:
Аноним
Дата:
18.11.03 08:20
Оценка:
А если есть оператор преобразования в указатель на функцию или ссылку на указатель на функцию, объект такого класса можно назвать функтором?
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Функтор — собирательный термин, который обозначает все виды сущностей в С++, к которым применим оператор вызова функции — '()'. Функторы сразу делятся на два подкласса — 1) обыкновенные функции (указатели на обыкновенные функции) к которым применяется встроенный оператор '()' и 2) функциональные объекты — объекты классов с перегруженным оператором '()'.
И еще связки (closure) объект.метод.
Поскольку в С++ (а не в диалекте Borland C++ Builder) такая сущность не существует отдельно от ее выполнения — то ее эмулируют, например, функциональным объектом-оберткой.
Криво выразился Андрей, поправь пожалуйста, если надо.
Здравствуйте, LaptevVV, Вы писали:
LVV>А затем, чтобы заменить указатели на функции при обработке сложных структур данных.
Нафига? LVV>С указателями, как ты понимаешь, хлопот больше, чем выгод.
С указателями на ФУНКЦИИ? Нука просвети. LVV>А функтор — это ОБЪЕКТ, который можно передавать и по значению.
Указатель на функцию тоже. LVV>Инкапсуляция и надежность программ повышаются.
Чем? LVV>А еще — можно состояния хранить — полей-то можно определить какие хочешь.
Функтор с сотоянием? Чему ты народ учишь...
Это такаяже кривь как и(НИ КОГДА ТАК НЕ ДЕЛАЙТЕ)
int fibonacci()
{
static int x1=1;
static int x2=1;
int x3=x1+x2;
x1=x2;
x2=x3;
retunr x3;
}
Изврат правда. Функтор с сотоянием ни чем не отличается. Вернее это и есть функтор с состоянием. LVV>Если более подробно, то надо в книжках читать. LVV>На эту тему много написано. LVV>Хотя бы у Александреску.
Почитать можно, а вот использовать не стоит. Лучше boost::function.
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
хъ LVV>> А еще — можно состояния хранить — полей-то можно определить какие LVV>> хочешь. W> Функтор с сотоянием? Чему ты народ учишь... W> Это такаяже кривь как и(НИ КОГДА ТАК НЕ ДЕЛАЙТЕ) W>
W> int fibonacci()
W> {
W> static int x1=1;
W> static int x2=1;
W> int x3=x1+x2;
W> x1=x2;
W> x2=x3;
W> retunr x3;
W> }
W>
W> Изврат правда. Функтор с сотоянием ни чем не отличается. Вернее это и W> есть функтор с состоянием.
Извиняюсь, что влез в дискуссию, но я бы не стал так категорично утверждать, что функтор-класс с состоянием полный отстой
Приведенный выше пример, конечно, показывает как не надо писать. Но иногда просто необходимо знать состояние предыдущего вызова:
Ну зачем же так сплеча
LVV>>А затем, чтобы заменить указатели на функции при обработке сложных структур данных. WH>Нафига?
Ну хотя бы для повышения эффективности (что ИМХО является очень весомым фактором). Дело в том, что компилятор обычно не "инлайнит" вызов функции через указатель, а вот вызов переопределенного operator() у объекта — легко. Подробности у Майерса в "Effective STL", совет 46.
LVV>>А еще — можно состояния хранить — полей-то можно определить какие хочешь. WH>Функтор с сотоянием? Чему ты народ учишь... WH>Это такаяже кривь как и(НИ КОГДА ТАК НЕ ДЕЛАЙТЕ)
Функторы бывают разные. Что ты скажешь, например, о таком?
class in_range
{
int begin_, end_;
public:
in_range(int begin, int end) : begin_(begin), end_(end) {}
bool operator () (int n) { return n >= begin_ && n < end; }
};
?
Или о стандартных биндерах? Или о семействе mem_fun?
Думаю, ты изменишь свое мнение о функторах с сотоянием.
Здравствуйте, WolfHound, Вы писали:
LVV>>А затем, чтобы заменить указатели на функции при обработке сложных структур данных. WH>Нафига?
Ага, а итераторы (хоть это и не функцторы) нафига придумали. Обходились бы указателями! LVV>>С указателями, как ты понимаешь, хлопот больше, чем выгод. WH>С указателями на ФУНКЦИИ? Нука просвети.
Потому что указатели. Типовые преобразования сделать — как два байта переслать. Функторы просто так не преобразуешь.
Хотя для реализации таблицы виртуальных функций именно указатели на функции используются, но ведь не зря их спрятали — уровень программирования повышается. LVV>>А функтор — это ОБЪЕКТ, который можно передавать и по значению. WH>Указатель на функцию тоже.
Ну да, он так и передается. Просто внутри функции, которая получила указатель на функцию можно через преобразование типов вызвать практически ЛЮБУЮ другую. С функтором так просто не получится. LVV>>Инкапсуляция и надежность программ повышаются. WH>Чем?
Именно из-за объектной обертки. WH>Почитать можно, а вот использовать не стоит. Лучше boost::function.
Нужно читать. А использовать — при необходимости.
Что-то уж больно воинственно
Давайте жить дружно!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, WolfHound, Вы писали:
LVV>>А еще — можно состояния хранить — полей-то можно определить какие хочешь. WH>Функтор с сотоянием? Чему ты народ учишь...
Функтор с состоянием — это разновидность функции с побочным эффектом.
Пример:
int fibo(int n)
{
int f;
... вычисляем ...
cout << "F(" << n << ")" << f << endl; // побочный эффектreturn f;
}
int fibo_once(int n)
{
static map<int,int> fn;
map<int,int>::const_iterator it = fn.find(n);
if(it == fn.end())
{
int f = fibo(n);
fn[n] = f; // еще один побочный эффектreturn f;
}
else return it->second;
}
Тоже, скажешь, так не делать? Тогда получим чистый функциональный язык, в котором любое выражение есть константа.
Другое практичное применение функторов с состояниями: callback для разнообразных enum-функций.
Например, посмотри, как делается перечисление шрифтов в виндовозе. В callback-функции ты запоминаешь каждый присланный шрифт, а по выходе из api-шного вызова — берешь полученную коллекцию и делаешь с ней что хочешь.
Здравствуйте, PM, Вы писали:
PM>Извиняюсь, что влез в дискуссию, но я бы не стал так категорично утверждать, что функтор-класс с состоянием полный отстой
А я бы стал. Особенно когда дело касается тех кто плохо понимает что делает. PM>Приведенный выше пример, конечно, показывает как не надо писать. Но иногда просто необходимо знать состояние предыдущего вызова:
Спасибо! Великолепный пример того как не надо делать. Не знаю как другие а я бы долго думал что тут происходит. И скорей всего бы не понял без заглядывания в хидер. Болие того у тебя там ошибка. Введи такую строку "blablazz" результат тебя удивит.
В данном случае нужен не функтор, а алгоритм
Примерно такой
std::cin не очень удачный источник ибо у него нет конца (возьми ifstream) цикл будет повторятся пока не введешь zz но это не суть важно.
Главное это решение болие понятно и универсально чем твое.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Bell, Вы писали:
B>Функторы бывают разные. Что ты скажешь, например, о таком?
хъ B>Или о стандартных биндерах? Или о семействе mem_fun? B>Думаю, ты изменишь свое мнение о функторах с сотоянием.
Следуя данной терминологии ВСЕ функторы (в том числе и функции) являются функторами с состоянием.
В моем понимании функтор с состоянием это такой функтор который помнит что с ним было при прошлом вызове. in_range этим не страдает.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, LaptevVV, Вы писали:
LVV>>>А затем, чтобы заменить указатели на функции при обработке сложных структур данных. WH>>Нафига? LVV>Ага, а итераторы (хоть это и не функцторы) нафига придумали. Обходились бы указателями!
А они тут причем? LVV>>>С указателями, как ты понимаешь, хлопот больше, чем выгод. WH>>С указателями на ФУНКЦИИ? Нука просвети. LVV>Потому что указатели. Типовые преобразования сделать — как два байта переслать. Функторы просто так не преобразуешь.
Код в студию.(только без reinterpret_cast и c-style cast)
LVV>>>Инкапсуляция и надежность программ повышаются. WH>>Чем? LVV>Именно из-за объектной обертки.
Не понял что тут инкапсулировать?
int (*fn_ptr)(int);
Ы?
WH>>Почитать можно, а вот использовать не стоит. Лучше boost::function. LVV>Нужно читать. А использовать — при необходимости.
Loki это учебная библиотека. И относится к ней надо соответствующи.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
К>int fibo(int n)
К>{
К> int f;
К> ... вычисляем ...
К> cout << "F(" << n << ")" << f << endl; // побочный эффект
К> return f;
К>}
К>
А вто так не делать однозначно К>
К>int fibo_once(int n)
К>{
К> static map<int,int> fn;
К> map<int,int>::const_iterator it = fn.find(n);
К> if(it == fn.end())
К> {
К> int f = fibo(n);
К> fn[n] = f; // еще один побочный эффект
К> return f;
К> }
К> else return it->second;
К>}
К>
К>Тоже, скажешь, так не делать? Тогда получим чистый функциональный язык, в котором любое выражение есть константа.
Да скажу.
А теперь в твою fibo_one начали передавать значения 1000, 999...1
К>Другое практичное применение функторов с состояниями: callback для разнообразных enum-функций. К>Например, посмотри, как делается перечисление шрифтов в виндовозе. В callback-функции ты запоминаешь каждый присланный шрифт, а по выходе из api-шного вызова — берешь полученную коллекцию и делаешь с ней что хочешь.
Те ты хочешь сказать что каждое решение МС образцом для подражания?
Ну например посмотри на FindFirstFile. Ы? Мне он нравится больше ибо на раз вписывается в концепцию input iterator.
Те можно написать примерно так
Здравствуйте, Юнусов Булат, Вы писали:
ЮБ>Неа, это "одноразовый" функтор какой то
ЮБ>Функторы реинкарнируются, а функции нет.
хъ
Генерация последовательности пожалуй единственное разумное применение. Но на столько редкое что я о нем забыл .
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, Bell, Вы писали:
B>>Функторы бывают разные. Что ты скажешь, например, о таком? WH>хъ
B>>Или о стандартных биндерах? Или о семействе mem_fun? B>>Думаю, ты изменишь свое мнение о функторах с сотоянием. WH>Следуя данной терминологии ВСЕ функторы (в том числе и функции) являются функторами с состоянием. WH>В моем понимании функтор с состоянием это такой функтор который помнит что с ним было при прошлом вызове. in_range этим не страдает.
Пример был очень хороший. После того как его увидел, не стал постить свой (менее выразительный и дублирующий уже сказанное), но если тебя не убедили, держи вдогонку:
задача — отсортировать точки по увеличению расстояния от заданной
Насчет состояний... Если я правильно понял, то под состоянием, ты понимаешь значения статических свойств класса. Это несколько расходится с формулировкой стандарта. Definitions
17.1.10 Object state
The current value of all nonstatic class members of an object. The state of an object can be obtained by using one or more observer functions