2013-02-11 2 views
2

у меня есть:Нахождение в станд :: вектор структур

struct MyStruct 
{ 
    char* name; 
    int* somethingElse; 
}; 

И мне нужно найти в std::vector<MyStruct*> элемент (с использованием std::find_if), чьи name является "XYZ" ... но ... Predicatestd::find_if (если я правильно понял), это простая функция, и она принимает указатель MyStruct, и я понятия не имею, где я могу указать дополнительное значение "XYZ", которое будет использоваться при сравнении.

Итак, как я могу использовать std::find_if или для этой цели? (Очевидно, что ищет хорошее решение, а не глобальной переменной, или просто пройти по списку, ....)

Спасибо, е

+2

Посмотрите функторы или лямбды. –

ответ

4

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

class finder 
{ 
    const char* name; 
public: 
    finder(const char* _name): name(_name) {} 

    bool operator()(MyStruct* elem) {return strcmp(elem->name, name) == 0;} 
}; 

finder f("sample"); 
std::find_if(myvector.begin(), myvector.end(), f); 
1

Predicate что-нибудь, что может иметь оператор () применяется к нему (с ожидаемым аргументом (-ами) и возвращает что-то конвертируемое в bool). Указателем на функцию является такая вещь, но и объект, который определяет operator().

+0

Предикат должен возвращать то, что можно проверить на ложность истины. – juanchopanza

0

Вы должны предоставить предикат, как это:

struct Comparator 
{ 
    Comparator(const char* find) : m_find(find){} 
    bool operator()(MyStruct* p) const 
    { 
     return strcmp(p->name, m_find) == 0; 
    } 

    const char* m_find; 
}; 

Тогда вы можете std::find_if так:

vector<MyStruct*>::iterator iter = std::find_if(vec.begin(), vec.end(), Comparator("XYZ")); 
if(iter != vec.end()) 
{ 
    MyStruct* p = *iter; 
} 

Или, если ваш компилятор поддерживает C++ 11 вы можете использовать лямбды и избавиться от предиката функтора:

auto it = std::find_if(vec.begin(), vec.end(), [](MyStruct* p) { return strcmp(p->name, "XYZ") == 0;}); 
2

У вас есть два варианта, либо использовать функторы или lamdas.

Использование функторов, необходимо создать новый класс (или структуру), конструктор принимает строку, которую вы хотите найти, то она имеет operator() функцию, которая вызывается std::find_if:

class my_finder 
{ 
    std::string search; 

public: 
    my_finder(const std::string& str) 
     : search(str) 
    {} 

    bool operator()(const MyStruct* my_struct) const 
     { return search == my_struct->name; } 
}; 

// ... 

std::find_if(std::begin(...), std::end(...), my_finder("XYZ")); 

Второго использование лямбда меньше кода, но требует последней версии компилятора, который может обрабатывать C++11 lambdas:

std::find_if(std::begin(...), std::end(...), [](const MyStruct* my_struct) 
    { return std::string("XYZ") == my_struct->name; }); 

Последние е xample можно даже обобщить далее:

using namespace std::placeholders; // For `_1` used below in `std::bind` 

// Declare a "finder" function, to find your structure 
auto finder = [](const MyStruct* my_struct, const std::string& to_find) { 
    return to_find == my_struct->name; 
}; 

auto xyz = std::find_if(std::begin(...), std::end(...), std::bind(finder, _1, "XYZ")); 
auto abc = std::find_if(std::begin(...), std::end(...), std::bind(finder, _1, "ABC")); 

Таким образом, лямбда может быть использована повторно.

3

Если вы используете C++ 11 и лямбда:

std::vector<MyStruct> mystructus; 
std::find_if(mystructus.begin(), mystructus.end(), 
      [](const MyStruct& ms){ return ms.name == std::string("XYZ"); }); 
Смежные вопросы