Вход на сайт
[C++] Иерархия функторов
NEW 20.11.06 12:56
в ответ rahimov80 20.11.06 12:41
Я не знаю, откуда ты вытащил свое определение для for_each. Вот так она определена в VC6:
template<class _II, class _Fn> inline
_Fn for_each(_II _F, _II _L, _Fn _Op)
{for (; _F != _L; ++_F)
_Op(*_F);
return (_Op); }
Речь идет о третьем параметре - функторе, который передается по значению.
20.11.06 17:55
в ответ Simple 20.11.06 12:56
Прекрасное определение, у меня такое же 
А что будет если задать _Fn как CFactor& ?!
Если мой ответ тебя не удовлетворит, то "поезжайте в Киев и спросите..." (c)
То есть проверь как работает:
for_each<list<CNode>::iterator, CBaseFactor&>(lstCNode.begin(), lstCNode.end(), theFactor)
как theFactor попробуй и CBaseFactor theFactor; и CDerivedFactor theFactor;
Удачи!

А что будет если задать _Fn как CFactor& ?!

Если мой ответ тебя не удовлетворит, то "поезжайте в Киев и спросите..." (c)
То есть проверь как работает:
for_each<list<CNode>::iterator, CBaseFactor&>(lstCNode.begin(), lstCNode.end(), theFactor)
как theFactor попробуй и CBaseFactor theFactor; и CDerivedFactor theFactor;
Удачи!
NEW 20.11.06 23:43
Во-первых, не вызовется, потому, что не скомпилируется. Если for_each сделать вида:
for_each<vector<int>::iterator, BaseFunctor&>
то передать туда как написали выше:
DerivedFunctor theFunctor;
будет нельзя. Если попытаться сделать нечто типа этого:
BaseFunctor bf1;
DerivedFunctor df;
BaseFunctor& bf2 = df;
то попытка вызвать:
for_each<vector<int>::iterator, BaseFunctor&>(vec.begin(), vec.end(), bf2);
будет тоже неудачной. Во-вторых, если бы это работало, тебе, вроде, совсем другое надо - для каждого элемeнта коллекции вызвать нужную функцию? Если да, то Мурр сказал в начале ответ - в коллекцию загоняем ссылки на базовый виртуальный класс, а функтор всего лишь дёргает виртуальную функцию из переданного ему элемента коллекции.
Dropbox - средство синхронизации и бэкапа файлов.
NEW 21.11.06 00:09
в ответ voxel3d 20.11.06 23:43
И в-третьих, какое вс╦ отношение имеет к процитированному куску из Сартра? Сорри, мне лень искать смотреть, но там, разве, не имеется в виду именно вот это использование for_each:
class functor ...
for_each(iter_begin, iter_end, functor())
и пишет он про то, что функтор должен быть "л╦гким" для создания копии? Т.к. здесь созда╦тся временный объект-функтор.
Dropbox - средство синхронизации и бэкапа файлов.
NEW 21.11.06 00:10
в ответ voxel3d 20.11.06 23:43
Во, во, я так и говорил: "иди ARM почитай" 

Ксати, все ваши примеры прекрасно будут работать: up-casting возможен всегда
Base b = d; Base* pB = pD; Base& b = d; etc.

В ответ на:
Во-вторых, если бы это работало,
- а у нас что, будет ли код работать или не будет, уже не от стандарта зависит, а от чего-то другого? Во-вторых, если бы это работало,

Ксати, все ваши примеры прекрасно будут работать: up-casting возможен всегда
Base b = d; Base* pB = pD; Base& b = d; etc.
NEW 21.11.06 00:18
Пардон, DerivedFunctor унаследовал не от BaseFunctor, а от unary_function<int, void>. Ок, работает, я был неправ, но пункт два это не отменяет - для всех элементов будет вызван один и тот же метод.
Dropbox - средство синхронизации и бэкапа файлов.
NEW 21.11.06 00:58
в ответ Simple 20.11.06 20:20
Ну и замечательно.
Теперь подведем итог, согласно вашей постановке задачи:
1. Если "состояния конкретного элемента массива" можно передать через полиморфизм (т.е. иерархия и т.д.), а тип документа предположим только один, то вариант "Murr/voxel3d": коллекция с ссылками на базовый класс, а функтор не требует полиморфизма, так как определяет документ, который только один.
2. Если "состояния конкретного элемента массива" не требует полиморфизм (может вы имеете в виду разный state в стате-машине внутри элемента
), а разные типы документов определяются через полиморфизм, то вы можете использовать for_each и передавать функтор (определяющий документ) через ссылку.
3. Если вам требуется полиморфизм и для элементов в массиве и для документов, то необходимо воспользоватся паттерном Визитор, как совершенно справедливо заметил scorpi_, так как "double dispatch"!
Ну что,всех примерил?
Теперь подведем итог, согласно вашей постановке задачи:
В ответ на:
Элементы массива преобразовываются в элементы некоего документа. Операция преобразования может отличаться для разных типов документов и состояния конкретного элемента массива.
Элементы массива преобразовываются в элементы некоего документа. Операция преобразования может отличаться для разных типов документов и состояния конкретного элемента массива.
1. Если "состояния конкретного элемента массива" можно передать через полиморфизм (т.е. иерархия и т.д.), а тип документа предположим только один, то вариант "Murr/voxel3d": коллекция с ссылками на базовый класс, а функтор не требует полиморфизма, так как определяет документ, который только один.
2. Если "состояния конкретного элемента массива" не требует полиморфизм (может вы имеете в виду разный state в стате-машине внутри элемента

3. Если вам требуется полиморфизм и для элементов в массиве и для документов, то необходимо воспользоватся паттерном Визитор, как совершенно справедливо заметил scorpi_, так как "double dispatch"!
Ну что,всех примерил?

NEW 21.11.06 08:41
в ответ rahimov80 21.11.06 00:58
В конечном итоге у меня получилось, что полиморфизм не требуется ни на одной стороне, но я все равно сделал по п. 3, потому что будет проще расширить,если что-то изменится. К тому же, функторы рекомендуется передавать по значению - не понял, почему, но верю Саттеру :)
> Ну что,всех примерил?
Примеряют штаны :-P
> Ну что,всех примерил?
Примеряют штаны :-P
NEW 21.11.06 08:45
в ответ voxel3d 21.11.06 00:18
Ты имеешь в виду, что п-м не работает? Так работает же.
#ifndef __TEST_CPP__
#define __TEST_CPP__
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
class Base : public unary_function<int, void>
{
public:
Base() {}
Base(const Base& base)
{
n_copied++;
}
void operator()(int num)
{
cout << num_op(num) << " ";
}
Base& operator=(const Base& base)
{
n_assigned++;
}
static int n_copied;
static int n_assigned;
private:
virtual int num_op(int num)
{
return num;
}
};
int Base::n_copied = 0;
int Base::n_assigned = 0;
class Derived : public Base
{
public:
Derived() {}
Derived(const Derived& d)
{
n_copied++;
}
private:
virtual int num_op(int num)
{
return num*num;
}
};
int main(int argc, char* argv[])
{
vector<int> coll;
for (int i = 0; i < 10; i++)
coll.push_back(i);
Base b;
Derived d;
cout << "n_copied = " << Base::n_copied << endl;
for_each<vector<int>::iterator, Base&>(coll.begin(), coll.end(), b);
cout << endl;
cout << "n_copied = " << Base::n_copied << endl;
for_each<vector<int>::iterator, Base&>(coll.begin(), coll.end(), d);
cout << endl;
cout << "n_copied = " << Derived::n_copied << endl;
return 0;
}
#endif
NEW 21.11.06 12:04
Совершенно справедливое решение: думать об возможности рассширения - это хороший стиль! 
Но и в случае Visitor, ты в CElement::Accept() сам Visitor == Functor должен передавать по ссылке.
Как там было: "иди GoF почитай"
(לגשר-to reconcile)

Но и в случае Visitor, ты в CElement::Accept() сам Visitor == Functor должен передавать по ссылке.
Как там было: "иди GoF почитай"

В ответ на:
> Ну что,всех примерил?
Примеряют штаны :-P
Вот проблема, как "легашер" пишется ещё помню לגשר, а вот в русском уже делаю ошибки > Ну что,всех примерил?
Примеряют штаны :-P

