Что такое функтор???
От: Amon-RA  
Дата: 18.11.03 06:45
Оценка:
привет все.
Люди, не объясните популярно, что такое функтор. Спасибо
Re: Что такое функтор???
От: Bell Россия  
Дата: 18.11.03 06:54
Оценка:
Здравствуйте, Amon-RA, Вы писали:

AR>привет все.

AR>Люди, не объясните популярно, что такое функтор. Спасибо

Это объект класса, имеющего переопределенный оператор operator ()


class func
{
   int n_;
public:
   func(int n) : n_(n) {}
   bool operator() (int n) { return n == n_; }
};

...

func functor;
Любите книгу — источник знаний (с) М.Горький
Re[2]: Что такое функтор???
От: Amon-RA  
Дата: 18.11.03 06:56
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, Amon-RA, Вы писали:


AR>>привет все.

AR>>Люди, не объясните популярно, что такое функтор. Спасибо

B>Это объект класса, имеющего переопределенный оператор operator ()



B>
B>class func
B>{
B>   int n_;
B>public:
B>   func(int n) : n_(n) {}
B>   bool operator() (int n) { return n == n_; }
B>};

B>...

B>func functor;
B>


И зачем оно надо и зачем обзывать его по особенному?
Re[3]: Что такое функтор???
От: LaptevVV Россия  
Дата: 18.11.03 06:59
Оценка:
Здравствуйте, Amon-RA, Вы писали:

AR>И зачем оно надо и зачем обзывать его по особенному?


А затем, чтобы заменить указатели на функции при обработке сложных структур данных.
С указателями, как ты понимаешь, хлопот больше, чем выгод.
А функтор — это ОБЪЕКТ, который можно передавать и по значению. Инкапсуляция и надежность программ повышаются.
А еще — можно состояния хранить — полей-то можно определить какие хочешь.
Если более подробно, то надо в книжках читать.
На эту тему много написано.
Хотя бы у Александреску.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Что такое функтор???
От: Андрей Тарасевич Беларусь  
Дата: 18.11.03 08:10
Оценка: 35 (2) +1
Здравствуйте, Amon-RA, Вы писали:

AR>привет все.

AR>Люди, не объясните популярно, что такое функтор. Спасибо

Функтор — собирательный термин, который обозначает все виды сущностей в С++, к которым применим оператор вызова функции — '()'. Функторы сразу делятся на два подкласса — 1) обыкновенные функции (указатели на обыкновенные функции) к которым применяется встроенный оператор '()' и 2) функциональные объекты — объекты классов с перегруженным оператором '()'.

Иногда под термином 'функтор' продразумевают только функциональные объекты. Это, строго говоря, некорректное употребление данного термина. Обычные функции и указатели на них тоже являются частными случаями функторов.
Best regards,
Андрей Тарасевич
Re[2]: Что такое функтор???
От: Аноним  
Дата: 18.11.03 08:20
Оценка:
А если есть оператор преобразования в указатель на функцию или ссылку на указатель на функцию, объект такого класса можно назвать функтором?
Re[2]: Что такое функтор???
От: Кодт Россия  
Дата: 18.11.03 09:20
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>Функтор — собирательный термин, который обозначает все виды сущностей в С++, к которым применим оператор вызова функции — '()'. Функторы сразу делятся на два подкласса — 1) обыкновенные функции (указатели на обыкновенные функции) к которым применяется встроенный оператор '()' и 2) функциональные объекты — объекты классов с перегруженным оператором '()'.


И еще связки (closure) объект.метод.

Поскольку в С++ (а не в диалекте Borland C++ Builder) такая сущность не существует отдельно от ее выполнения — то ее эмулируют, например, функциональным объектом-оберткой.

Криво выразился Андрей, поправь пожалуйста, если надо.
Перекуём баги на фичи!
Re[4]: Что такое функтор???
От: WolfHound  
Дата: 18.11.03 09:55
Оценка: -4
Здравствуйте, 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) А. Эйнштейн
Re[5]: Что такое функтор???
От: PM  
Дата: 18.11.03 10:23
Оценка:
Здраствуйте, WolfHound. Вы писали:

хъ
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> есть функтор с состоянием.
Извиняюсь, что влез в дискуссию, но я бы не стал так категорично утверждать, что функтор-класс с состоянием полный отстой
Приведенный выше пример, конечно, показывает как не надо писать. Но иногда просто необходимо знать состояние предыдущего вызова:
/// Accumulate characters until terminator char doubled
class chars_accumulator2
{
public:
 chars_accumulator2(char terminator) : term_(terminator), num_terms_(0) {}
 bool operator()(char ch)
 {
  if ( 2 == num_terms_ ) 
  {
    result.erase( result.end()-2, result.end() );
    return false;
  }
  num_terms_ = ( term_ == ch )? num_terms_ + 1 : 0;
  result.push_back(ch);
  return true;
 }
 std::string result;
private:
 char term_;
 size_t num_terms_;
};

...
std::string s("blablazzbla");
chars_accumulator2 camm2('z');
for (std::string::iterator it = s.begin(); it != s.end(); ++it)
{
    if ( !camm2(*it) ) break;
}

assert ( camm2.result == "blabla");
Posted via RSDN NNTP Server 1.7 "Bedlam"
Re[5]: Что такое функтор???
От: Bell Россия  
Дата: 18.11.03 10:28
Оценка: 2 (2)
Здравствуйте, WolfHound, Вы писали:

Ну зачем же так сплеча

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?
Думаю, ты изменишь свое мнение о функторах с сотоянием.
Любите книгу — источник знаний (с) М.Горький
Re[5]: Что такое функтор???
От: LaptevVV Россия  
Дата: 18.11.03 10:42
Оценка:
Здравствуйте, WolfHound, Вы писали:

LVV>>А затем, чтобы заменить указатели на функции при обработке сложных структур данных.

WH>Нафига?
Ага, а итераторы (хоть это и не функцторы) нафига придумали. Обходились бы указателями!
LVV>>С указателями, как ты понимаешь, хлопот больше, чем выгод.
WH>С указателями на ФУНКЦИИ? Нука просвети.
Потому что указатели. Типовые преобразования сделать — как два байта переслать. Функторы просто так не преобразуешь.
Хотя для реализации таблицы виртуальных функций именно указатели на функции используются, но ведь не зря их спрятали — уровень программирования повышается.
LVV>>А функтор — это ОБЪЕКТ, который можно передавать и по значению.
WH>Указатель на функцию тоже.
Ну да, он так и передается. Просто внутри функции, которая получила указатель на функцию можно через преобразование типов вызвать практически ЛЮБУЮ другую. С функтором так просто не получится.
LVV>>Инкапсуляция и надежность программ повышаются.
WH>Чем?
Именно из-за объектной обертки.
WH>Почитать можно, а вот использовать не стоит. Лучше boost::function.
Нужно читать. А использовать — при необходимости.
Что-то уж больно воинственно
Давайте жить дружно!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[5]: Что такое функтор???
От: Кодт Россия  
Дата: 18.11.03 11:45
Оценка: 1 (1)
Здравствуйте, 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-шного вызова — берешь полученную коллекцию и делаешь с ней что хочешь.
Перекуём баги на фичи!
Re[5]: Что такое функтор???
От: Юнусов Булат Россия  
Дата: 18.11.03 12:11
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Функтор с сотоянием? Чему ты народ учишь...

WH>Это такаяже кривь как и(НИ КОГДА ТАК НЕ ДЕЛАЙТЕ)
WH>
WH>int fibonacci()
...
WH>

WH>Изврат правда. Функтор с сотоянием ни чем не отличается. Вернее это и есть функтор с состоянием.

Неа, это "одноразовый" функтор какой то

Функторы реинкарнируются, а функции нет.
int fibonacci()
{
    static int x1 = 1;
    static int x2 = 1;
    int x3 = x1 + x2;
    x1 = x2;
    x2 = x3;
    return x3;
}

struct fibo
{
    int x1, x2;
    
    fibo() : x1(1), x2(1)
    {
    }
    
    int operator()()
    {
        int x3 = x1 + x2;
        x1 = x2;
        x2 = x3;
        return x3;
    }
};

int main(int argc, char* argv[])
{
    std::generate_n(std::ostream_iterator<int>(std::cout, "\n"), 5, fibonacci);
    std::generate_n(std::ostream_iterator<int>(std::cout, "\n"), 5, fibonacci);
    
    std::cout << std::endl;
    
    std::generate_n(std::ostream_iterator<int>(std::cout, "\n"), 5, fibo());
    std::generate_n(std::ostream_iterator<int>(std::cout, "\n"), 5, fibo());
    
    return 0;
}
Re[6]: Что такое функтор???
От: WolfHound  
Дата: 18.11.03 14:56
Оценка:
Здравствуйте, PM, Вы писали:

PM>Извиняюсь, что влез в дискуссию, но я бы не стал так категорично утверждать, что функтор-класс с состоянием полный отстой

А я бы стал. Особенно когда дело касается тех кто плохо понимает что делает.
PM>Приведенный выше пример, конечно, показывает как не надо писать. Но иногда просто необходимо знать состояние предыдущего вызова:
Спасибо! Великолепный пример того как не надо делать. Не знаю как другие а я бы долго думал что тут происходит. И скорей всего бы не понял без заглядывания в хидер. Болие того у тебя там ошибка. Введи такую строку "blablazz" результат тебя удивит.
В данном случае нужен не функтор, а алгоритм
Примерно такой
template
    <class input_iter
    ,class output_iter
    >
void repeat_until_terminator_doubled
    (input_iter begin
    ,input_iter end
    ,output_iter out
    ,typename std::iterator_traits<input_iter>::value_type terminator
    )
{
    typedef typename std::iterator_traits<input_iter>::value_type value_type;
    if(begin==end)return;
    value_type val[2];
    bool flag=false;//Используем свойства bool'ов false==0 true==1
    val[flag]=*begin;
    while(true)
    {
        ++begin;
        if(begin==end)
        {
            *out=val[flag];
            return;
        }
        flag=!flag;
        val[flag]=*begin;
        if(val[0]==val[1])
            return;
        *out=val[!flag];
        ++out;
    }
};

Использование
    std::string str("asdasfzasdzasfdzzaas");
    std::string res;
    repeat_until_terminator_doubled(str.begin(), str.end(), std::back_inserter(res), 'z');

или
    repeat_until_terminator_doubled
        (std::istream_iterator<char>(std::cin)
        ,std::istream_iterator<char>()
        ,std::ostream_iterator<char>(std::cout)
        ,'z'
        );

std::cin не очень удачный источник ибо у него нет конца (возьми ifstream) цикл будет повторятся пока не введешь zz но это не суть важно.
Главное это решение болие понятно и универсально чем твое.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: Что такое функтор???
От: WolfHound  
Дата: 18.11.03 15:04
Оценка:
Здравствуйте, WolfHound, Вы писали:

fix
заменить
        if(val[0]==val[1])
            return;

на
        if(val[0]==terminator&&val[1]==terminator)
            return;
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: Что такое функтор???
От: WolfHound  
Дата: 18.11.03 15:07
Оценка:
Здравствуйте, Bell, Вы писали:

B>Функторы бывают разные. Что ты скажешь, например, о таком?

хъ
B>Или о стандартных биндерах? Или о семействе mem_fun?
B>Думаю, ты изменишь свое мнение о функторах с сотоянием.
Следуя данной терминологии ВСЕ функторы (в том числе и функции) являются функторами с состоянием.
В моем понимании функтор с состоянием это такой функтор который помнит что с ним было при прошлом вызове. in_range этим не страдает.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: Что такое функтор???
От: WolfHound  
Дата: 18.11.03 15:13
Оценка:
Здравствуйте, 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) А. Эйнштейн
Re[6]: Что такое функтор???
От: WolfHound  
Дата: 18.11.03 15:34
Оценка:
Здравствуйте, Кодт, Вы писали:

И где тут запоминают состояние функции?
К>
К>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.
Те можно написать примерно так
    std::for_each
        (find_file_iterator("c:\\*.*")
        ,find_file_iterator()
        ,print_file_info
        );
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: Что такое функтор???
От: WolfHound  
Дата: 18.11.03 15:36
Оценка:
Здравствуйте, Юнусов Булат, Вы писали:

ЮБ>Неа, это "одноразовый" функтор какой то


ЮБ>Функторы реинкарнируются, а функции нет.

хъ
Генерация последовательности пожалуй единственное разумное применение. Но на столько редкое что я о нем забыл .
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: Что такое функтор???
От: FreshMeat Россия http://www.rsdn.org
Дата: 18.11.03 16:17
Оценка: 2 (1)
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Bell, Вы писали:


B>>Функторы бывают разные. Что ты скажешь, например, о таком?

WH>хъ


B>>Или о стандартных биндерах? Или о семействе mem_fun?

B>>Думаю, ты изменишь свое мнение о функторах с сотоянием.
WH>Следуя данной терминологии ВСЕ функторы (в том числе и функции) являются функторами с состоянием.
WH>В моем понимании функтор с состоянием это такой функтор который помнит что с ним было при прошлом вызове. in_range этим не страдает.
Пример был очень хороший. После того как его увидел, не стал постить свой (менее выразительный и дублирующий уже сказанное), но если тебя не убедили, держи вдогонку:
задача — отсортировать точки по увеличению расстояния от заданной
struct less_dist : std::binary_function<bool, point2, point2>
{
    explicit less_dist( const point2& base ) : m_base( base ) {}
    bool operator()( const point2& p0, const point2& p1 )
    {
        return sqr_dist( m_base, p0 ) < sqr_dist( m_base, p1 );
    }
private:
    const point2 m_base;
};
...
// сортируем элементы контейнера по расстоянию от точки
std::sort( v.begin(), v.end(), less_dist( point2(0, 0) ) );


Насчет состояний... Если я правильно понял, то под состоянием, ты понимаешь значения статических свойств класса. Это несколько расходится с формулировкой стандарта.
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
Хорошо там, где мы есть! :)
Re[8]: Что такое функтор???
От: FreshMeat Россия http://www.rsdn.org
Дата: 18.11.03 16:30
Оценка:
Совсем забыл одну цитату... Мейерс называет объекты подобные in_range "чистыми".
Вот его формулировка:
"Чистой" функцией называется функция, возвращаемое значение которой зависит только от параметров. Если f — "чистая" функция, а x и y — объекты, то возвращаемое значение f(x, y) может измениться только в случае изменения x или y (Эффективное использование STL, совет 39)
Определение очень легко интерполируется на функторы... Спор получается был просто терминологическим...
Хорошо там, где мы есть! :)
Re[7]: Что такое функтор???
От: PM  
Дата: 18.11.03 17:03
Оценка:
Здраствуйте, WolfHound. Вы писали:

W> Здравствуйте, PM, Вы писали:

PM>> Приведенный выше пример, конечно, показывает как не надо писать. Но
PM>> иногда просто необходимо знать состояние предыдущего вызова:
W> Спасибо! Великолепный пример того как не надо делать. Не знаю как другие
W> а я бы долго думал что тут происходит. И скорей всего бы не понял без
W> заглядывания в хидер. Болие того у тебя там ошибка. Введи такую строку
W> "blablazz" результат тебя удивит. В данном случае нужен не функтор, а
W> алгоритм Примерно такой
[код поскипан]
W> std::cin не очень удачный источник ибо у него нет конца (возьми
W> ifstream) цикл будет повторятся пока не введешь zz но это не суть важно.
W> Главное это решение болие понятно и универсально чем твое.
Ладно, а если рассматривать функтор с состоянием как необходимое в некотором случае решение и предотвратить возможность неправильного его использования (например, запретив копирование) ?
Стандартные алгоритмы, принимающие функторы по значению, в таком случае не скомпилируются
class stateful_functor 
{
public:
    stateful_functor(int initial_state) : state_(initial_state) {}
    void operator()(int x)
    {
        // здесь какие-то действия, зависящие от state_
        if (state_)       --state_;
        else                ++state_;
    }
private:
    stateful_functor(const stateful_functor&);
    stateful_functor& operator=(const stateful_functor&);
    int state_;
};
//...
typedef std::vector<int> VI;
VI vi;
std::for_each(vi.begin(), vi.end(), stateful_functor(0) );
Posted via RSDN NNTP Server 1.7 "Bedlam"
Re[7]: Что такое функтор???
От: Кодт Россия  
Дата: 18.11.03 17:17
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Кодт, Вы писали:


WH>И где тут запоминают состояние функции?

К>>
К>>  cout << "F(" << n << ")" << f << endl; // побочный эффект
К>>

Как где? На экране.
Результат вычисления чистой функции не зависит от количества прогонов

WH>А теперь в твою fibo_one начали передавать значения 1000, 999...1


Это был пример. Хорошо, давай перепишем.
int fibo(int n)
{
  if(n < 2) return 1;

  // Критическую секцию для потокобезопасности писать не стану. Обойдесса
  static map<int,int> fn;
  static int known = 0;

  if(n < known) return fn[n];
  int f = fibo(n-2) + fibo(n-1);
  known = n;
  fn[n] = f;
  return f;
}


WH>Те ты хочешь сказать что каждое решение МС образцом для подражания?

WH>Ну например посмотри на FindFirstFile. Ы? Мне он нравится больше ибо на раз вписывается в концепцию input iterator.
WH>Те можно написать примерно так
WH>
WH>    std::for_each
WH>        (find_file_iterator("c:\\*.*")
WH>        ,find_file_iterator()
WH>        ,print_file_info
WH>        );
WH>

Насчет твоего примера. print_file_info имеет "выхлоп" (побочные эффекты, не влияющие на последовательность работы программы — например, вывод в cout). И всё?
Если не всё — значит, print_file_info умеет дотягиваться до каких-то внешних по отношению к нему самому, но внутренних по отношению к клиенту, переменных. То есть это, на самом деле, умело задрапированный output iterator.

А уж методы iterator'ов (особенно инкремент) — это точно функции с состоянием.

Далее.
Посмотрим, что можно сделать с input iterator'ами.
* перемотать
* взять данные
* проверить (применить предикат)
* преобразовать
* сосчитать
Окей, для всего этого есть алгоритмы STL.
Теперь встает вопрос: что дешевле — выполнить декомпозицию исходной задачи на набор базовых алгоритмов и примитивных функторов (предикаты и трансформаторы) или написать один функтор с внутренним состоянием, который проверяет, перематывает, считает и трансформирует?

Как всегда, бывает по-разному. Иногда — декомпозиция, иногда (реже) комбайн.

Наконец.
Насчет решений МС — я могу понять, откуда это берется.
Вот две альтернативы:
void WINAPI enumSomething(params, callback) // в недрах библиотеки
{
  context (params);
  for(context.init(); context.okay(); context.next())
  {
    callback(context.result());
  }
}

//////////

HANDLE WINAPI begin_enumSomething(params)
{
  pcontext = new context(params);
  pcontext->init();
  return (HANDLE)pcontext;
}
bool next_enumSomething(HANDLE h, result& r)
{
  pcontext = (context*)h;
  if(!pcontext->okay()) return false;
  r = pcontext->result();
  return true;
}
void close_enumSomething(HANDLE h)
{
  delete (context*)h;
}

Вот и сравни: одна функция или три, плюс внутренняя куча для хранения контекстов.
Перекуём баги на фичи!
Re[9]: Что такое функтор???
От: WolfHound  
Дата: 18.11.03 20:57
Оценка:
Здравствуйте, FreshMeat, Вы писали:

FM>Совсем забыл одну цитату... Мейерс называет объекты подобные in_range "чистыми".

FM>Вот его формулировка:
FM>"Чистой" функцией называется функция, возвращаемое значение которой зависит только от параметров. Если f — "чистая" функция, а x и y — объекты, то возвращаемое значение f(x, y) может измениться только в случае изменения x или y (Эффективное использование STL, совет 39)
FM>Определение очень легко интерполируется на функторы... Спор получается был просто терминологическим...
Если следовать данной терминологии я считаю что в 99.9999% случаев можно применять только чистые функторы. А новичкам не чистые функторы применять категорически противопоказано.
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: Что такое функтор???
От: WolfHound  
Дата: 18.11.03 20:57
Оценка:
Здравствуйте, FreshMeat, Вы писали:

FM>Пример был очень хороший. После того как его увидел, не стал постить свой (менее выразительный и дублирующий уже сказанное), но если тебя не убедили, держи вдогонку:

FM>задача — отсортировать точки по увеличению расстояния от заданной
Если следовать нижеприведенной терминологии less_dist и in_range чистые функторы против них я ни чего не имею.
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: Что такое функтор???
От: WolfHound  
Дата: 18.11.03 20:58
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Как где? На экране.

К>Результат вычисления чистой функции не зависит от количества прогонов
Изменения на экране можно считать одним из возвращаемых значений функции(кто сказал что должен быть только один результат )причем в данном случае результат будет один и тотже при одних и техже параметрах функции. Те данная функция (если следовать предложеной Мейерсом терминологии)чистая.

К>Это был пример. Хорошо, давай перепишем.

Если уж пишешь так пиши оптимально.
size_t fibo(size_t n)
{
    static std::vector<size_t> cache(2, 1);
    while(n>cache.size())
        cache.push_back(*(cache.end()-1)+*(cache.end()-2));
    return cache[n-1];
}

Результат данной функции также не зависит от параметров следовательно и она чистая.
Так что мой наезд на конкретно эту функцию был поспешен.

К>Насчет решений МС — я могу понять, откуда это берется.

Если ты считаешь что я не могу то ты сильно ошибаешься.
К>Вот две альтернативы:
Так иногда проще разработчику этой функции(хотя с точки зрения пользователя )
К>void WINAPI enumSomething(params, callback) // в недрах библиотеки
К>{
К>  context (params);
К>  for(context.init(); context.okay(); context.next())
К>  {
К>    callback(context.result());
К>  }
К>}


А так смотрим внимательно
Конструктор
К>HANDLE WINAPI begin_enumSomething(params)
К>{
К>  pcontext = new context(params);
К>  pcontext->init();
К>  return (HANDLE)pcontext;
К>}

метод
К>bool next_enumSomething(HANDLE h, result& r)
К>{
К>  pcontext = (context*)h;
К>  if(!pcontext->okay()) return false;
К>  r = pcontext->result();
К>  return true;
К>}

деструктор
К>void close_enumSomething(HANDLE h)
К>{
К>  delete (context*)h;
К>}

Болие того эти три функции реализуют нормальный input iterator с которым каллбеки по удобству ни в какое сравнение не идут.

Короче гдето когдато както функция с состоянием может сработать но почти наверняка выдет боком.
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: Что такое функтор???
От: WolfHound  
Дата: 18.11.03 20:58
Оценка:
Здравствуйте, PM, Вы писали:

PM>Ладно, а если рассматривать функтор с состоянием как необходимое в некотором случае решение и предотвратить возможность неправильного его использования (например, запретив копирование) ?

Давай без абстракций на них можно много бреда насочинять. Ты пальцем покажи где без них ни туды и ни сюды или хотябы работы на порядок больше.
PM>Стандартные алгоритмы, принимающие функторы по значению, в таком случае не скомпилируются
В том то и лажа что не скомпилируются следовательно их придется писать самуму
К томуже в твоем случае это вобще не причем ошибка в логике твоего функтрора.
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: Что такое функтор???
От: PM  
Дата: 19.11.03 10:48
Оценка:
Здраствуйте, WolfHound. Вы писали:

PM>> Ладно, а если рассматривать функтор с состоянием как необходимое в

PM>> некотором случае решение и предотвратить возможность неправильного его
PM>> использования (например, запретив копирование) ?
W> Давай без абстракций на них можно много бреда насочинять. Ты пальцем
W> покажи где без них ни туды и ни сюды или хотябы работы на порядок
W> больше.

Вот пример реального кода. Сорри за большой объем
/// XML sequence processor base class
template<typename Char>
struct processor
{
 virtual ~processor() {} //NOTE: may be not necessarily?
 /// Process sequence.
 /// @return True if processing complete.
 virtual bool operator()(Char ch) = 0;
 /// Result 
 typename xml::char_traits<Char>::string_type result;
};

/// Accumulate characters until terminator char doubled
template<typename Char>
class chars_accumulator2 : public processor<Char>
{
public:
 chars_accumulator2(Char terminator) : term_(terminator), num_terms_(0)
 {}
 bool operator()(Char ch)
 {
  if ( 2 == num_terms_ ) return false;
  num_terms_ = ( term_ == ch )? num_terms_ + 1 : 0;
  result.push_back(ch);
  return true;
 }
private:
 Char term_;
 size_t num_terms_;
};

/// Apply processor for each element in range while true.
/// @return  Iterator to next not applied element.
template<typename Char, typename InputIterator>
inline InputIterator apply_while(InputIterator first, InputIterator last, 
         processor<Char>& proc)
{
 for ( ; first != last; ++first )
  if ( !proc(*first) ) break;
 return first;
}

template<typename Char, typename InputIterator>
inline InputIterator parse_comment(InputIterator first, InputIterator last)
{
 // ...
 // parse comment body
 chars_accumulator2<Char> accum2(xml::char_traits<Char>::minus);
 first = apply_while(++first, last, accum2);
 first = check_end_tag<Char>(first, last);
 assert( accum2.result.size() >= 2 );
 // erase extra minuses
 accum2.result.resize( accum2.result.size() - 2 );
 handler.on_comment(accum2.result);
 return first;
}


Есть куча функций, подобных parse_comment. В каждой из них вызывается apply_while, в которую передается ссылка на потомок processor'а. Через эту же ссылку приходит и результат. Налицо вызов apply_while с побочным эффектом. Мне интересно, насколько обоснованно такое решение с твой точки зрения.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Re[10]: Что такое функтор???
От: jazzer Россия Skype: enerjazzer
Дата: 19.11.03 13:26
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, FreshMeat, Вы писали:


FM>>Совсем забыл одну цитату... Мейерс называет объекты подобные in_range "чистыми".

FM>>Вот его формулировка:
FM>>"Чистой" функцией называется функция, возвращаемое значение которой зависит только от параметров. Если f — "чистая" функция, а x и y — объекты, то возвращаемое значение f(x, y) может измениться только в случае изменения x или y (Эффективное использование STL, совет 39)
FM>>Определение очень легко интерполируется на функторы... Спор получается был просто терминологическим...
WH>Если следовать данной терминологии я считаю что в 99.9999% случаев можно применять только чистые функторы. А новичкам не чистые функторы применять категорически противопоказано.

Только вот если у твоего класса-функтора есть куча переменных, которые образуют его состояние — то состояние есть, хотя при этом каждый объект этого класса-функтора будет "чистой" функцией, просто разные обекты этого класса будут разными "чистыми" функциями.

Т.е.
struct Incr
{
   Incr(int x) : x_(x) {}
   void operator()(int& i) { i += x_; }
private:
   int x_;
};

Incr incr1(1), incr2(2);

и incr1, и incr2 являются "чистыми" функциями, но делают разное, хотя являются экземплярами одного и того же класса-функтора.

Более того, никто не мешает тебе предусмотреть какой-нть метод типа set_x, между вызовами которого функтор является чистым.

В общем, решений море, и охаивать огульно все функторы с состояниями сразу я бы не стал.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[11]: Что такое функтор???
От: WolfHound  
Дата: 19.11.03 14:01
Оценка:
Здравствуйте, jazzer, Вы писали:

Да е мое. Я уже заколебался повторять что следуя данной терминологии ЛЮБОЙ функтор есть функтор с состоянием. И указатель на функцию сюдаже попадает.
Под функторами с состоянием я имел в виду не чистые функторы. Млин.

И мой пимер в том посте был о томже.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: Что такое функтор???
От: WolfHound  
Дата: 19.11.03 14:13
Оценка:
Здравствуйте, PM, Вы писали:

PM>Вот пример реального кода. Сорри за большой объем

Это не много.


Это к чертовой бабушке. Не нужен он.
PM>/// XML sequence processor base class
PM>template<typename Char>
PM>struct processor
PM>{
PM> virtual ~processor() {} //NOTE: may be not necessarily?
PM> /// Process sequence.
PM> /// @return True if processing complete.
PM> virtual bool operator()(Char ch) = 0;
PM> /// Result 
PM> typename xml::char_traits<Char>::string_type result;
PM>};


Про это я уже говорил
PM>/// Accumulate characters until terminator char doubled
PM>template<typename Char>
PM>class chars_accumulator2 : public processor<Char>
PM>{
PM>public:
PM> chars_accumulator2(Char terminator) : term_(terminator), num_terms_(0)
PM> {}
PM> bool operator()(Char ch)
PM> {
PM>  if ( 2 == num_terms_ ) return false;
PM>  num_terms_ = ( term_ == ch )? num_terms_ + 1 : 0;
PM>  result.push_back(ch);
PM>  return true;
PM> }
PM>private:
PM> Char term_;
PM> size_t num_terms_;
PM>};


3 параметер должен принемать ссылку на функтор, а не на его базу.
PM>/// Apply processor for each element in range while true.
PM>/// @return  Iterator to next not applied element.
PM>template<typename Char, typename InputIterator>
PM>inline InputIterator apply_while(InputIterator first, InputIterator last, 
PM>         processor<Char>& proc)
PM>{
PM> for ( ; first != last; ++first )
PM>  if ( !proc(*first) ) break;
PM> return first;
PM>}


PM>template<typename Char, typename InputIterator>
PM>inline InputIterator parse_comment(InputIterator first, InputIterator last)
PM>{
PM> // ...
PM> // parse comment body
PM> chars_accumulator2<Char> accum2(xml::char_traits<Char>::minus);
PM> first = apply_while(++first, last, accum2);
PM> first = check_end_tag<Char>(first, last);
PM> assert( accum2.result.size() >= 2 );
PM> // erase extra minuses
PM> accum2.result.resize( accum2.result.size() - 2 );
PM> handler.on_comment(accum2.result);
PM> return first;
PM>}


PM>Есть куча функций, подобных parse_comment. В каждой из них вызывается apply_while, в которую передается ссылка на потомок processor'а. Через эту же ссылку приходит и результат. Налицо вызов apply_while с побочным эффектом. Мне интересно, насколько обоснованно такое решение с твой точки зрения.

У меня есть смутное сомненье что ты както странно парсер пишешь. Их обычно на конечном автомате делают. А твоя система на него както не похожа.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: Что такое функтор???
От: PM  
Дата: 19.11.03 14:55
Оценка:
Здраствуйте, WolfHound. Вы писали:

PM>> Вот пример реального кода. Сорри за большой объем

W> Это не много.
W>
W> Это к чертовой бабушке. Не нужен он.
W>
 PM>> /// XML sequence processor base class
 PM>> template<typename Char>
 PM>> struct processor
 PM>> {
 PM>> };
 W>

См. ответ для apply_while

W> Про это я уже говорил

W>
 PM>> /// Accumulate characters until terminator char doubled
 PM>> template<typename Char>
 PM>> class chars_accumulator2 : public processor<Char>
 PM>> {
 PM>> };
 W>

У меня это пока работает. В предыдущих постах я сокращал его структуру, может где-то и облажался

W> 3 параметер должен принемать ссылку на функтор, а не на его базу.

/// Apply processor for each element in range while true.
/// @return  Iterator to next not applied element.
template<typename Char, typename InputIterator>
inline InputIterator apply_while(InputIterator first, InputIterator last, processor<Char>& proc);

Если мы здесь будем принимать ссылку на функтор, то придется добавить параметр шаблона для типа функтора. Это приведет к увеличению количества инстанцирований apply_while на количество используемых мной функторов. Преимуществ от этого я не вижу Объявив базовый абстрактный класс processor мы ограничиваем область неправильного(?) применения apply_while.
Но это не особо принципиально. Можно написать что-то типа
template<typename Char, typename InputIterator, typename Functor>
inline InputIterator apply_while(InputIterator first, InputIterator last, Functor& proc);

но всё равно это будет вызов с побочным эффектом.

А если сделать так
template<typename Char, typename InputIterator, typename OutputIterator,  typename Functor>
inline InputIterator apply_while(InputIterator first, InputIterator last, OutputIterator dst, Functor& proc)
{
    for ( ; first != last!; ++first, ++dst)
    {
        if ( !proc(*first) ) break;
        *dst = ??? // здесь мы все равно должны дернуть proc, чтобы узнать результат его работы, кторого может и не быть
    }
    return first;
}


[дальнейший код поскипан]
W> У меня есть смутное сомненье что ты както странно парсер пишешь. Их
W> обычно на конечном автомате делают. А твоя система на него както не
W> похожа.
Грубо говоря, parse_comment, parse_element и т.п. — это обработка переходов из одного состояния в другое, вынесенная наружу.
Если интересно, скачай сам парсер и посмотри — он не очень большой.
Мне будет очень интересно узнать твое мнение об архитектуре как таковой, так и о реализации в частности.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Re[12]: Что такое функтор???
От: WolfHound  
Дата: 19.11.03 15:28
Оценка:
Здравствуйте, PM, Вы писали:

PM>Грубо говоря, parse_comment, parse_element и т.п. — это обработка переходов из одного состояния в другое, вынесенная наружу.

PM>Если интересно, скачай сам парсер и посмотри — он не очень большой.
PM>Мне будет очень интересно узнать твое мнение об архитектуре как таковой, так и о реализации в частности.
Потом посмотрю. Вот примено как я вижу парсер.
Практически не тестировал. Со спецификацией xml не сверялся.
#include "stdafx.h"

template<class input_iter_t>
struct xml_parser
{
    int deep;
    input_iter_t cur;
    input_iter_t end;
    void check(bool condition, const std::string& msg="unknown error.")
    {
        if(!condition)
            throw std::string(msg);
    }

    bool is_end()
    {
        return cur==end;
    }
    char get()
    {
        return *cur;
    }
    void next()
    {
        ++cur;
    }
    void skip_space()
    {
        while(!is_end()&&isspace(get()))
            next();
    }

    void tag()
    {
        check(!is_end());
        std::string open;
        while(!is_end()&&isalnum(get()))
        {
            open+=get();
            next();
        }
        check(!is_end()&&get()=='>');
        next();

        ++deep;
        body();
        --deep;

        check(!is_end()&&get()=='/');
        next();
        std::string close;
        while(!is_end()&&isalnum(get()))
        {
            close+=get();
            next();
        }
        check(!is_end()&&get()=='>');
        next();
        check(open==close);
    }

    void comment()
    {
        check(!is_end()&&get()=='!');    next();
        check(!is_end()&&get()=='-');    next();
        check(!is_end()&&get()=='-');    next();
        int count=0;
        while(!is_end())
        {
            count
                =(get()=='-')
                ?count+1 
                :0;
            next();
            if(count==2)
            {
                check(!is_end());
                if(get()=='>')
                    break;
                count=1;
            }
        }
        check(!is_end());
        next();
    }

    void body()
    {
        check(!is_end());
        while(true)
        {
            skip_space();
            if(cur==end)
            {
                if(deep==0)
                    return;
                check(false);
            }
            switch(get())
            {
            case '<':
                next();
                check(!is_end());
                switch(get())
                {
                    case '/':
                        return;
                    break;
                    case '!':
                        comment();
                    break;
                    default:
                        tag();
                    break;
                }
            break;
            default:
                check(false);
            break;
            }
        }
    }

    void parse_begin(input_iter_t _cur, input_iter_t _end)
    {
        deep=0;
        cur=_cur;
        end=_end;
        body();
    }
};
int main()
{
    std::string src=
        "    <asd>"
        "        <qwe>"
        "            <!---->"
        "            <!--"
        "        ->        qeqwed"
        "        <!-        sacsdf"
        "        --        <qwe>"
        "                </qwe>"
        "            ---->"
        "        </qwe>"
        "    </asd>"
        ;
    try
    {
        xml_parser<std::string::iterator> p;
        p.parse_begin(src.begin(), src.end());
    }
    catch(const std::string& msg)
    {
        std::cout<<msg<<std::endl;
    }
    return 0;
}
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[13]: Что такое функтор???
От: PM  
Дата: 20.11.03 07:38
Оценка:
Здраствуйте, WolfHound. Вы писали:

W> Потом посмотрю. Вот примено как я вижу парсер.

W> Практически не тестировал. Со спецификацией xml не сверялся.
[код поскипан]
У меня примерно так же, только более строго и обработка сущностей XML вынесена в отдельные функции (большей частью для удобства тестирования )
Posted via RSDN NNTP Server 1.7 "Bedlam"
Re[10]: Что такое функтор???
От: Артур Россия  
Дата: 20.11.03 09:03
Оценка:
Здравствуйте, PM, Вы писали:

А где у тебя запрещён конструктор копирования?

по идее STL алгоритмы могут копировать передаваемый функтор, и передавать в другие алгоритмы по значению. Например:

template <class ForwardIterator, class Predicate>
ForwardIterator remove_if(ForwardIterator first, ForwardIterator last,
Predicate pred) {
first = find_if(first, last, pred);
ForwardIterator next = first;
return first == last ? first : remove_copy_if(++next, last, first, pred);
}


Как выход можно использовать внешнее состояние:
template<typename Char>
class chars_accumulator2 : public processor<Char>
{
public:
chars_accumulator2(Char terminator, size_t& num_terms) : term_(terminator), num_terms_(num_terms)
{}
//....skip
Char term_;
size_t& num_terms_;
};
... << RSDN@Home 1.1.0 stable >>
Re[11]: Что такое функтор???
От: PM  
Дата: 20.11.03 09:15
Оценка:
Здраствуйте, Артур. Вы писали:

А> А где у тебя запрещён конструктор копирования?

В реальном коде он не запрещен, т.к. функторы используются только с apply_while
А> по идее STL алгоритмы могут копировать передаваемый функтор, и
А> передавать в другие алгоритмы по значению. Например:
хъ
Это я знаю

А> Как выход можно использовать внешнее состояние:

А>
 А> template<typename Char>
 А> class chars_accumulator2 : public processor<Char>
 А> {
 А> public:
 А> chars_accumulator2(Char terminator, size_t& num_terms) :
 А> term_(terminator), num_terms_(num_terms) {}
 А> //....skip
 А> Char term_;
 А> size_t& num_terms_;
 А> };
 А>

num_terms — это особенность реализации chars_accumulator2. По-моему, нарушение инкапсуляции еще хуже чем функтор с состоянием.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Re[12]: Что такое функтор???
От: Артур Россия  
Дата: 20.11.03 09:38
Оценка:
Здравствуйте, PM, Вы писали:


PM>num_terms — это особенность реализации chars_accumulator2. По-моему, нарушение инкапсуляции еще хуже чем функтор с состоянием.


Тока и всего?
template<typename Char>
class chars_accumulator2 : public processor<Char>
{
public:
struct external_state
{
    external_state():num_terms(0){}
    size_t num_terms;
};
chars_accumulator2(Char terminator, external_state& estate) : term_(terminator), num_terms_(estate.num_terms)
{}
//....skip
Char term_;
size_t& num_terms_;
};
... << RSDN@Home 1.1.0 stable >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.