2010-11-25 4 views
0

Я использую в первый раз функцию std :: find_if в коде C++. Примеры и логика, которые я хочу выполнить, довольно просты, но почему-то я не могу заставить ее работать.C++, find_if не работает

Я создал класс «Finder» таким образом:

/** 
    * @class message_by_id_finder 
    * @brief A class to find the matching lane wrapper 
    */ 
    class message_by_id_finder 
    { 
    public: 
    /** @brief constructor */ 
    explicit message_by_id_finder(int id) : 
    m_myMessage(id) { 
    } 

    /** @brief the comparing function */ 
    bool operator()(const AppMessage& message) const { 
    return message.messageId == m_myMessage; 
    } 

    private: 
    /// @brief The id of the searched object 
    int m_myMessage; 
    }; 

Затем я использую его следующим образом:

// Loop messages 
for (vector<AppMessage>::iterator it = messages.begin(); it != messages.end() ; ++it) { 
// Match message with the registered by the App 
AppMessage m = *it; 
vector<AppMessage>::iterator it2 = find_if(m_messages.begin(), m_messages.end(), message_by_id_finder(m)); 
if (it2 != m_messages.end()) { 
    // FOUND! 
} else { 
    // NOT FOUND 
} 
} 

Я петельные вектор m_messages и есть члены, которые соответствуют ид но it2 всегда 0x00. Я делаю что-то особенное неправильно?

спасибо, что заранее.

PD: Только в случае, другая часть кодов, полезных для понимания проблемы:

/** 
    * @struct AppMessage 
    * @brief Information of a message carrying a result of the App. 
    */ 
    struct AppMessage { 
     int messageId;  
     float payloadValue;  
    }; 
+1

Ваша реализация `operator()` является анти-шаблоном. Код должен быть записан как `return id = m_myMessage ;, вместо этого. ** Никогда ** писать `if (condition) return true; else возвращает false; `. – 2010-11-25 15:22:30

+1

Отсутствует близкая скобка для `operator()`. `it2! = m_messages.end()` означает, что идентификатор сообщения * был * найден, а не то, что это не так. Я предлагаю вам написать полную программу, которая компилирует и демонстрирует поведение, которое вас удивляет, и задайте вопрос об этой программе. В противном случае вы могли бы просто получить ответы на опечатки весь день, ни один из которых не присутствует в вашем реальном коде. – 2010-11-25 15:27:37

+0

Спасибо, Конрад. Но, не используя шаблон, который вы упоминаете, вызывает ошибку? Кроме того, 'return id = m_myMessage;' верный? Не должно быть 'return id == m_myMessage;'? – Julen 2010-11-25 15:27:59

ответ

2

Вашего предикат должен взять объект типа итерации, то есть AppMessage в вашем случае.

Так что, если вы замените оператор() что-то вроде этого, я думаю, вы получите ближе к чему-то работа:

bool operator()(const AppMessage& am) const { 
    return am.messageId == m_myMessage; 
} 
2

Вы должны понимать, что find_if делает внутренне для того, чтобы правильно использовать его. Сайт cplusplus reference предлагает некоторые базовые фрагменты кода, которые могут помочь понять, что на самом деле делает алгоритм (, но помните, что это просто «псевдокод» для образовательной цели, а не фактическая реализация). Это то, что этот сайт дает как описание std::find_if:

template<class InputIterator, class Predicate> 
InputIterator find_if (InputIterator first, InputIterator last, Predicate pred) 
{ 
    for (; first!=last ; first++) if (pred(*first)) break; 
    return first; 
} 

Что вы можете видеть, что предикат вызывается для каждого элемента в последовательности. Здесь у вас есть std::vector<AppMessage>, поэтому предоставляемый предикат должен быть вызван с помощью AppMessage.

Изменения вы предикат к этому следует сделать трюк:

class message_by_id_finder 
{ 
public: 
    /** @brief constructor */ 
    explicit message_by_id_finder(int id) : 
     m_myMessage(id) 
    {} 

    /** @brief the comparing function */ 
    bool operator()(const AppMessage &appMessage) const { 
     return appMessage.messageId == m_myMessage; 
    } 

private: 
    /// @brief The id of the searched object 
    const int m_myMessage; 
} 

Также обратите внимание, что я сделал operator() и m_myMessage сопзЬ (почему, потому что я могу?!).

0

Ваша логическая логика неверна для find_if, что, скорее всего, приведет к вашей ошибке.

Как бы то ни было, если ваши векторы не очень короткие, и вы делаете это много раз, find и find_if очень неэффективны, поскольку они являются линейной сложностью. Ваш использует 2 цикла, которые делают его O (M * N), где M и N - длина ваших коллекций.

Big-O, как его называют, является одним из основных ключей к эффективному программированию.

Если ваши коллекции отсортированы, set_intersect - это способ получить все элементы, находящиеся в обеих коллекциях, которые являются O (M + N). Если это не так, вы можете отсортировать один из них, после чего ваш поиск будет O (M log N) или O (N log M), зависящий от того, который вы отсортировали. Если один намного длиннее другого, и вы сортируете более длинный, O (M log N) более эффективен, чем O (M + N) (типичная ситуация заключается в поиске нескольких элементов в таблице базы данных, в которой много записей . Даже запуск таблицы один раз будет неэффективным по сравнению с несколькими индексированными поисками).

Смежные вопросы