Вы можете использовать предикатную версию transform
, если таковая была. Там нет ни одного, но это очень легко написать:
template<class InputIterator, class OutputIterator, class UnaryFunction, class Predicate>
OutputIterator transform_if(InputIterator first,
InputIterator last,
OutputIterator result,
UnaryFunction f,
Predicate pred)
{
for (; first != last; ++first)
{
if( pred(*first) )
*result++ = f(*first);
}
return result;
}
Тогда вам понадобится способ составить несколько предикатов, чтобы вы могли выразить что-то вроде find_if( begin, end, condition1 && condition2 )
. Это, опять же, легко написать:
template<typename LHS, typename RHS> struct binary_composite : public std::unary_function<Gizmo, bool>
{
binary_composite(const LHS& lhs, const RHS& rhs) : lhs_(&lhs), rhs_(&rhs) {};
bool operator()(const Gizmo& g) const
{
return lhs_->operator()(g) && rhs_->operator()(g);
}
private:
const LHS* lhs_;
const RHS* rhs_;
};
Наконец, вам нужна штуковина, которую transform_if
использует для преобразования ссылки на объект в указатель на объект. Сюрприз, сюрприз, легко написать ...
template<typename Obj> struct get_ptr : public std::unary_function<Obj, Obj*>
{
Obj* operator()(Obj& rhs) const { return &rhs; }
};
Давайте соединим все это с конкретным примером. Gizmo
ниже - объект, коллекция которого у вас есть. У нас есть 2 предиката find_letter
и find_value
, по которым мы хотим найти совпадения в нашем основном vector
. transform_if
- это предикатная версия transform
, get_ptr
преобразует ссылку на объект в указатель, а binary_composite
связывает воедино два компонента.
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <functional>
#include <vector>
using namespace std;
struct Gizmo
{
string name_;
int value_;
};
struct find_letter : public std::unary_function<Gizmo, bool>
{
find_letter(char c) : c_(c) {}
bool operator()(const Gizmo& rhs) const { return rhs.name_[0] == c_; }
private:
char c_;
};
struct find_value : public std::unary_function<Gizmo, int>
{
find_value(int v) : v_(v) {};
bool operator()(const Gizmo& rhs) const { return rhs.value_ == v_; }
private:
int v_;
};
template<typename LHS, typename RHS> struct binary_composite : public std::unary_function<Gizmo, bool>
{
binary_composite(const LHS& lhs, const RHS& rhs) : lhs_(&lhs), rhs_(&rhs) {};
bool operator()(const Gizmo& g) const
{
return lhs_->operator()(g) && rhs_->operator()(g);
}
private:
const LHS* lhs_;
const RHS* rhs_;
};
template<typename LHS, typename RHS> binary_composite<LHS,RHS> make_binary_composite(const LHS& lhs, const RHS& rhs)
{
return binary_composite<LHS, RHS>(lhs, rhs);
}
template<class InputIterator, class OutputIterator, class UnaryFunction, class Predicate>
OutputIterator transform_if(InputIterator first,
InputIterator last,
OutputIterator result,
UnaryFunction f,
Predicate pred)
{
for (; first != last; ++first)
{
if( pred(*first) )
*result++ = f(*first);
}
return result;
}
template<typename Obj> struct get_ptr : public std::unary_function<Obj, Obj*>
{
Obj* operator()(Obj& rhs) const { return &rhs; }
};
int main()
{
typedef vector<Gizmo> Gizmos;
Gizmos gizmos;
// ... fill the gizmo vector
typedef vector<Gizmo*> Found;
Found found;
transform_if(gizmos.begin(), gizmos.end(), back_inserter(found), get_ptr<Gizmo>(), binary_composite<find_value,find_letter>(find_value(42), find_letter('a')));
return 0;
}
EDIT:
Основанный на итеративном подходе sbi , вот предикатная версия copy
, которая больше соответствует общей парадигме STL и может использоваться с back_insert_iterator
для достижения того, что в этом случае требуется , Он даст вам vector
объекта, а не итераторов или индексов, поэтому transform_if
, который я разместил выше, все же лучше для этого использования, чем copy_if
. Но вот оно ...
template<class InputIterator, class OutputIterator, class Predicate>
OutputIterator copy_if(InputIterator first,
InputIterator last,
OutputIterator result,
Predicate pred)
{
for (; first != last; ++first)
{
if( pred(*first) )
*result++ = *first;
}
return result;
}