Здравствуйте, 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
Совсем забыл одну цитату... Мейерс называет объекты подобные in_range "чистыми".
Вот его формулировка:
"Чистой" функцией называется функция, возвращаемое значение которой зависит только от параметров. Если f — "чистая" функция, а x и y — объекты, то возвращаемое значение f(x, y) может измениться только в случае изменения x или y (Эффективное использование STL, совет 39)
Определение очень легко интерполируется на функторы... Спор получается был просто терминологическим...
Здраствуйте, 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) );
Здравствуйте, 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>
Насчет твоего примера. print_file_info имеет "выхлоп" (побочные эффекты, не влияющие на последовательность работы программы — например, вывод в cout). И всё?
Если не всё — значит, print_file_info умеет дотягиваться до каких-то внешних по отношению к нему самому, но внутренних по отношению к клиенту, переменных. То есть это, на самом деле, умело задрапированный output iterator.
А уж методы iterator'ов (особенно инкремент) — это точно функции с состоянием.
Далее.
Посмотрим, что можно сделать с input iterator'ами.
* перемотать
* взять данные
* проверить (применить предикат)
* преобразовать
* сосчитать
Окей, для всего этого есть алгоритмы STL.
Теперь встает вопрос: что дешевле — выполнить декомпозицию исходной задачи на набор базовых алгоритмов и примитивных функторов (предикаты и трансформаторы) или написать один функтор с внутренним состоянием, который проверяет, перематывает, считает и трансформирует?
Как всегда, бывает по-разному. Иногда — декомпозиция, иногда (реже) комбайн.
Наконец.
Насчет решений МС — я могу понять, откуда это берется.
Вот две альтернативы:
Здравствуйте, 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) А. Эйнштейн
Здравствуйте, FreshMeat, Вы писали:
FM>Пример был очень хороший. После того как его увидел, не стал постить свой (менее выразительный и дублирующий уже сказанное), но если тебя не убедили, держи вдогонку: FM>задача — отсортировать точки по увеличению расстояния от заданной
Если следовать нижеприведенной терминологии less_dist и in_range чистые функторы против них я ни чего не имею.
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Кодт, Вы писали:
К>Как где? На экране. К>Результат вычисления чистой функции не зависит от количества прогонов
Изменения на экране можно считать одним из возвращаемых значений функции(кто сказал что должен быть только один результат )причем в данном случае результат будет один и тотже при одних и техже параметрах функции. Те данная функция (если следовать предложеной Мейерсом терминологии)чистая.
К>Это был пример. Хорошо, давай перепишем.
Если уж пишешь так пиши оптимально.
Результат данной функции также не зависит от параметров следовательно и она чистая.
Так что мой наезд на конкретно эту функцию был поспешен.
К>Насчет решений МС — я могу понять, откуда это берется.
Если ты считаешь что я не могу то ты сильно ошибаешься. К>Вот две альтернативы:
Так иногда проще разработчику этой функции(хотя с точки зрения пользователя )
Здравствуйте, PM, Вы писали:
PM>Ладно, а если рассматривать функтор с состоянием как необходимое в некотором случае решение и предотвратить возможность неправильного его использования (например, запретив копирование) ?
Давай без абстракций на них можно много бреда насочинять. Ты пальцем покажи где без них ни туды и ни сюды или хотябы работы на порядок больше. PM>Стандартные алгоритмы, принимающие функторы по значению, в таком случае не скомпилируются
В том то и лажа что не скомпилируются следовательно их придется писать самуму
К томуже в твоем случае это вобще не причем ошибка в логике твоего функтрора.
... << RSDN@Home 1.1 beta 2 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здраствуйте, WolfHound. Вы писали:
PM>> Ладно, а если рассматривать функтор с состоянием как необходимое в PM>> некотором случае решение и предотвратить возможность неправильного его PM>> использования (например, запретив копирование) ? W> Давай без абстракций на них можно много бреда насочинять. Ты пальцем W> покажи где без них ни туды и ни сюды или хотябы работы на порядок W> больше.
Вот пример реального кода. Сорри за большой объем
/// XML sequence processor base classtemplate<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 doubledtemplate<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 с побочным эффектом. Мне интересно, насколько обоснованно такое решение с твой точки зрения.
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, FreshMeat, Вы писали:
FM>>Совсем забыл одну цитату... Мейерс называет объекты подобные in_range "чистыми". FM>>Вот его формулировка: FM>>"Чистой" функцией называется функция, возвращаемое значение которой зависит только от параметров. Если f — "чистая" функция, а x и y — объекты, то возвращаемое значение f(x, y) может измениться только в случае изменения x или y (Эффективное использование STL, совет 39) FM>>Определение очень легко интерполируется на функторы... Спор получается был просто терминологическим... WH>Если следовать данной терминологии я считаю что в 99.9999% случаев можно применять только чистые функторы. А новичкам не чистые функторы применять категорически противопоказано.
Только вот если у твоего класса-функтора есть куча переменных, которые образуют его состояние — то состояние есть, хотя при этом каждый объект этого класса-функтора будет "чистой" функцией, просто разные обекты этого класса будут разными "чистыми" функциями.
Да е мое. Я уже заколебался повторять что следуя данной терминологии ЛЮБОЙ функтор есть функтор с состоянием. И указатель на функцию сюдаже попадает.
Под функторами с состоянием я имел в виду не чистые функторы. Млин.
И мой пимер в том посте был о томже.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
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>Есть куча функций, подобных parse_comment. В каждой из них вызывается apply_while, в которую передается ссылка на потомок processor'а. Через эту же ссылку приходит и результат. Налицо вызов apply_while с побочным эффектом. Мне интересно, насколько обоснованно такое решение с твой точки зрения.
У меня есть смутное сомненье что ты както странно парсер пишешь. Их обычно на конечном автомате делают. А твоя система на него както не похожа.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здраствуйте, 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 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 и т.п. — это обработка переходов из одного состояния в другое, вынесенная наружу.
Если интересно, скачай сам парсер и посмотри — он не очень большой.
Мне будет очень интересно узнать твое мнение об архитектуре как таковой, так и о реализации в частности.
Здравствуйте, PM, Вы писали:
PM>Грубо говоря, parse_comment, parse_element и т.п. — это обработка переходов из одного состояния в другое, вынесенная наружу. PM>Если интересно, скачай сам парсер и посмотри — он не очень большой. PM>Мне будет очень интересно узнать твое мнение об архитектуре как таковой, так и о реализации в частности.
Потом посмотрю. Вот примено как я вижу парсер.
Практически не тестировал. Со спецификацией xml не сверялся.
Здраствуйте, WolfHound. Вы писали:
W> Потом посмотрю. Вот примено как я вижу парсер. W> Практически не тестировал. Со спецификацией xml не сверялся.
[код поскипан]
У меня примерно так же, только более строго и обработка сущностей XML вынесена в отдельные функции (большей частью для удобства тестирования )
по идее 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);
}
Здраствуйте, Артур. Вы писали:
А> А где у тебя запрещён конструктор копирования?
В реальном коде он не запрещен, т.к. функторы используются только с apply_while А> по идее STL алгоритмы могут копировать передаваемый функтор, и А> передавать в другие алгоритмы по значению. Например:
хъ
Это я знаю
А> Как выход можно использовать внешнее состояние: А>