Как я могу скрыть функтор в С++ (STL)?

У меня есть функция, чтобы найти значение:

struct FindPredicate
{

    FindPredicate(const SomeType& t) : _t(t) {
    }
    bool operator()(SomeType& t) {
      return t == _t;
    }

private:
    const SomeType& _t;
};

bool ContainsValue(std::vector<SomeType>& v, SomeType& valueToFind) {
    return find_if(v.begin(), v.end(), FindPredicate(valueToFind)) != v.end();
}

Теперь я хотел бы написать функцию, которая проверяет, удовлетворяют ли все элементы вектора предикату:

bool AllSatisfy(std::vector<SomeType>& v) {
    /* ... */
}

Одним из решений является использование алгоритма std::count_if.

Кто-нибудь знает решение, которое предполагает отрицание предиката?

Ответы

Ответ 1

Лучшим решением является использование функциональной библиотеки STL. Получив предикат из unary_function<SomeType, bool>, вы сможете использовать функцию not1, которая делает именно то, что вам нужно (т.е. Отрицает унарный предикат).

Вот как вы могли это сделать:

struct FindPredicate : public unary_function<SomeType, bool>
{
    FindPredicate(const SomeType& t) : _t(t) {}

    bool operator()(const SomeType& t) const {
      return t == _t;
    }

private:
    const SomeType& _t;
};

bool AllSatisfy(std::vector<SomeType>& v, SomeType& valueToFind)
{
    return find_if(v.begin(), 
                   v.end(), 
                   not1(FindPredicate(valueToFind))) == v.end();
}

Если вы хотите перевернуть свое собственное решение (то есть, IMHO, а не лучший вариант...), ну, вы можете написать другой предикат, который является отрицанием первого:

struct NotFindPredicate
{

    NotFindPredicate(const SomeType& t) : _t(t) {
    }
    bool operator()(SomeType& t) {
      return t != _t;
    }

private:
    const SomeType& _t;
};

bool AllSatisfy(std::vector<SomeType>& v) {
    return find_if(v.begin(), 
                   v.end(), 
                   NotFindPredicate(valueToFind)) == v.end();
}

Или вы могли бы сделать лучше и написать шаблонный функтор-отрицатель, например:

template <class Functor>
struct Not
{
    Not(Functor & f) : func(f) {}

    template <typename ArgType>
    bool operator()(ArgType & arg) { return ! func(arg); }

  private:
    Functor & func;
};

который вы можете использовать следующим образом:

bool AllSatisfy(std::vector<SomeType>& v, SomeType& valueToFind)
{
    FindPredicate f(valueToFind);
    return find_if(v.begin(), v.end(), Not<FindPredicate>(f)) == v.end();
}

Конечно, последнее решение лучше, потому что вы можете повторно использовать структуру Not с каждым вашим функтором.

Ответ 2

См. функтор библиотеки std not1, он возвращает функтор, который не является логическим, а не тем, что бы вы ни дали,.

Вы должны иметь возможность сделать что-то вроде:

bool AllSatisfy(std::vector<SomeType>& v, SomeType& valueToFind) {
    return find_if(v.begin(), v.end(), not1(FindPredicate(valueToFind))) != v.end();
}

Ответ 3

В первый раз, когда я использовал not1, я задавался вопросом, почему его просто не называли not.

Ответ немного меня удивил (см. комментарий).

Ответ 4

Поскольку вы используете его, вам не нужен функтор FindPredicate, так как в примере вы проверяете только равенство.

bool all_equal(std::vector<SomeType>& v, SomeType& valueToFind)
{
   return v.end() == find_if(v.begin(), v.end(), std::bind1st (equal_to (), valueToFind) );
}

bool all_not_equal( std::vector<SomeType>& v, SomeType &valueToFind ) {
{
   return v.end() == find_if(v.begin(), v.end(), std::bind1st (not_equal_to (), valueToFind) );
}

И вы можете просто создать этот шаблон самостоятельно.

template< typename InputIterator , typename Predicate >
bool test_all( InputIterator first, InputIterator last, Predicate pred )
{
  return last == find_if( first, last, pred );
}

test_all( v.begin(), v.end(), std::bind1st( not_equals_to_( value )) );