Как я могу отменить функтор в C ++ (STL)? - PullRequest
14 голосов
/ 05 ноября 2008

У меня есть функция для поиска значения:

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.

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

Ответы [ 4 ]

20 голосов
/ 05 ноября 2008

Лучшее решение - использовать функциональную библиотеку 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 с каждым необходимым вам функтором.

7 голосов
/ 05 ноября 2008

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

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

bool AllSatisfy(std::vector<SomeType>& v, SomeType& valueToFind) {
    return find_if(v.begin(), v.end(), not1(FindPredicate(valueToFind))) != v.end();
}
2 голосов
/ 05 ноября 2008

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

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

0 голосов
/ 08 ноября 2008

Поскольку вы используете его, вам не нужен функтор 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 )) );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...