STL алгоритмы: for_each_if
От: lomezych  
Дата: 09.02.04 13:50
Оценка:
Значить так.

Имеется абстрактный базовый класс.
class Foo 
{
public:
// ...    
    virtual bar mf(int) = 0;
// ...
    virtual void generator() = 0;
// ...
}

Потом создаётся много-много производных... и все они живут в
std::vector<Foo*> sequence;

Также имеетя некий manager, который делает с этим вектором много чего.

Хотелось бы выполнения функции в for_each(...) при каком-то условии. Написали for_each_if.
template <class InputIterator, class Predicate, class Function>
void for_each_if( InputIterator first, InputIterator last, Function f, Predicate pred )
{
    while ( first != last ) { 
        if ( pred( *first ) )
            f( *first++ ); 
        else
            first++;
    }
}

Тааакс.. на чём мы значит остановились.. ааа даа... Понадобился мне, значить, предикат, чтобы делал проверку на range. Окей... тоже написали:
template <class T> class in_range
    : public std::unary_function<T, bool> 
{
    T min;
    T max;

public:
    explicit in_range(const T& _min, const T& _max) : min(_min), max(_max) { }
    bool operator()( const T& val ) const { return ( val >= min && val <= max); }
};

Значить, тапереча, если у нас будет
std::vector<int> seq;

то можна найти, допустим, первое число в диапазоне (min...max)
std::vector<int>::iterator res = find_if(seq.begin(),
                                         seq.end(), 
                                         in_range<int>(min,max)
                                        );

Есть и другая запись, собсна, того же действа,
std::vector<int>::iterator res = find_if(seq.begin(),
                                         seq.end(),
                                         compose2(logical_and<bool>(),
                                                  bind2nd(greater_equal<int>(), min),
                                                  bind2nd(less_equal<int>(), max)
                                                 )
                                        );

но адаптер compose2 не является частью стандарта так что остаётся 1ый вариант... на худой конец можно выдрать код из какого-нть SGI STL.

Значит в чём загвоздка. Хотелось бы на месте mim и max увидеть значения, возвращаемые Foo::mf(int).
Те что-то типа:
for_each_if(sequence.begin(), sequence.end(), mem_fun(&Foo::generator), in_range<bar>(Foo::mf(1), Foo::mf(2)));
// тока не бейте!! :))  это так... чтоб ход мыслей продемонстрировать...

На данный момент имеется несколько специализаций для in_range, заточенных под vector<Foo*>,
но если их число будет расти это не есть хорошо. Хотелось бы какого-нть более универсального подхода.

Жду советов и коментов!
... << RSDN@Home 1.1.3 beta 1 >>
Re: STL алгоритмы: for_each_if
От: ArtDenis Россия  
Дата: 09.02.04 15:35
Оценка:
Здравствуйте, lomezych, Вы писали:

L>Значить так.


Во первых, переделаем in_range:
template <class T>
bool in_range (const T& _min, const T& _max, const T& val )
{
  return ( val >= _min && val <= _max);
}


Теперь при помощи буста твоя задача решаема:
  for_each_if
  (
    sequence.begin(),
    sequence.end(),
    boost::mem_fn(&Foo::generator),
    boost::bind
    (
      in_range<bar>,
      boost::bind(&Foo::mf, _1, 1),
      boost::bind(&Foo::mf, _1, 2),
      10 // а для какого числа будем искать вхождение в диапазон? Я заменил его на 10
    )  
  );


Правда, в задаче не понятно, какое число нужно передать в in_range для выяснения, входит ли оно в диапазон.
... << RSDN@Home 1.1.2 stable >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[2]: STL алгоритмы: for_each_if
От: lomezych  
Дата: 09.02.04 17:48
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Во первых, переделаем in_range:

AD>
AD>template <class T>
AD>bool in_range (const T& _min, const T& _max, const T& val )
AD>{
AD>  return ( val >= _min && val <= _max);
AD>}
AD>

Было бы наверно лучше описать "in less<> terms". Хотя ладно... это не главное.

AD>Теперь при помощи буста твоя задача решаема:

AD>
AD>  for_each_if
AD>  (
AD>    sequence.begin(),
AD>    sequence.end(),
AD>    boost::mem_fn(&Foo::generator),
AD>    boost::bind
AD>    (
AD>      in_range<bar>,
AD>      boost::bind(&Foo::mf, _1, 1),
AD>      boost::bind(&Foo::mf, _1, 2),
AD>      10 // а для какого числа будем искать вхождение в диапазон? Я заменил его на 10
AD>    )  
AD>  );
AD>


AD>Правда, в задаче не понятно, какое число нужно передать в in_range для выяснения, входит ли оно в диапазон.


Да, блин, сорри... писал в попыхах... опечатался...На самом деле надо вот как:
min и мах — это как раз подставляемые значения.. а для выяснения, входит ли в диапазон — это как раз должно быть значение возвращаемое Foo::mf. Т.е. как я понял должно быть вот так:
for_each_if
(
    sequence.begin(),
    sequence.end(),
    boost::mem_fn(&Foo::generator),
    boost::bind
    (
        in_range<bar>,
        min,    // тут всё
        max,    // ясно
        boost::bind(&Foo::mf, _1, value_passed_to_Foo_mf_function) // что собсна проверяем, входит ли в диапазон
    )  
);


Значит теперь усложним задачу. Получилось так, что надо предварительно надо перед сравнением переделать. Допустим есть функция (может быть как и член Foo, так и некая static).
baz barTobaz(bar);

Те меня интересует можно ли будет написать что-то вроде:
for_each_if
(
    sequence.begin(),
    sequence.end(),
    boost::mem_fn(&Foo::generator),
    boost::bind
    (
        in_range<baz>,
            min_baz,    // тут всё
            max_baz,    // ясно
            boost::bind(
                ptr_fn(barTobaz), // не уверен что в booste'е именно так
                _1,
                boost::bind(&Foo::mf, _1, value_passed_to_Foo_mf_function)  // что собсна проверяем, входит ли в диапазон
            )
    )  
);

С boost'ом я не очень знаком... Но решение конечно достаточно простое... Спасибо ArtDenis'у.
Но хотелось бы всё-таки уложиться в рамки стандарта STL.

Спасибо.... ждём-с ответа.
... << RSDN@Home 1.1.3 beta 1 >>
Re[3]: STL алгоритмы: for_each_if
От: ArtDenis Россия  
Дата: 09.02.04 18:11
Оценка:
Здравствуйте, lomezych, Вы писали:

L>Да, блин, сорри... писал в попыхах... опечатался...На самом деле надо вот как:

L>min и мах — это как раз подставляемые значения.. а для выяснения, входит ли в диапазон — это как раз должно быть значение возвращаемое Foo::mf.
Тогда нужно оставить оригинальный in_range (как в самом первом посте)

L>Значит теперь усложним задачу. Получилось так, что надо предварительно надо перед сравнением переделать. Допустим есть функция (может быть как и член Foo, так и некая static).


Вот так:

  for_each_if
  (
      sequence.begin(),
      sequence.end(),
      boost::mem_fn(&Foo::generator),
      boost::bind
      (
        in_range<bar>(min, max),
        boost::bind( Foo::barTobaz, boost::bind(&Foo::mf, _1, value_passed_to_Foo_mf_function) )
      )
  );


IMHO, три вложенных bind — это извращение. Лучше напиши обычный цикл вместо for_each_if с нормальными вызывами всех функций.

PS: сейчас кто-нибудь придёт и напишет тебе вариант с boost::lambda, но это будет ещё большим извращением.
... << RSDN@Home 1.1.2 stable >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.