Как std:: найти, используя объект сравнения?
Я запутался насчет интерфейса std::find
, Почему это не займет Compare
объект, который говорит ему, как сравнить два объекта?
Если бы я мог пройти Compare
объект, который я мог бы заставить следующий код работать, где я хотел бы сравнить по значению, а не просто сравнивать значения указателя напрямую:
typedef std::vector<std::string*> Vec;
Vec vec;
std::string* s1 = new std::string("foo");
std::string* s2 = new std::string("foo");
vec.push_back(s1);
Vec::const_iterator found = std::find(vec.begin(), vec.end(), s2);
// not found, obviously, because I can't tell it to compare by value
delete s1;
delete s2;
Следующий рекомендуемый способ сделать это?
template<class T>
struct MyEqualsByVal {
const T& x_;
MyEqualsByVal(const T& x) : x_(x) {}
bool operator()(const T& y) const {
return *x_ == *y;
}
};
// ...
vec.push_back(s1);
Vec::const_iterator found =
std::find_if(vec.begin(), vec.end(),
MyEqualsByVal<std::string*>(s2)); // OK, will find "foo"
3 ответа
find
не может быть перегружен для получения унарного предиката вместо значения, потому что это необязательный параметр шаблона. Так что если вы позвонили find(first, last, my_predicate)
, может возникнуть потенциальная неоднозначность, хотите ли вы, чтобы предикат оценивался для каждого члена диапазона, или хотите ли вы найти элемент диапазона, равный самому предикату (это может быть диапазон предикатов для всех разработчики стандартных библиотек знают или заботятся, или value_type
итератора может быть конвертируемым как в тип предиката, так и в его argument_type
). Отсюда необходимость find_if
идти под отдельным именем.
find
мог быть перегружен, чтобы принять необязательный двоичный предикат, в дополнение к искомому значению. Но захват значений в функторах, как вы сделали, является настолько стандартной техникой, что я не думаю, что это будет огромный выигрыш: это, безусловно, никогда не нужно, так как вы всегда можете достичь того же результата с find_if
,
Если вы получили find
Вы хотели, вам все равно придется написать функтор (или использовать повышение), так как <functional>
не содержит ничего, чтобы разыменовать указатель. Однако ваш функтор будет немного проще в качестве двоичного предиката, либо вы можете использовать указатель на функцию, так что это будет скромный выигрыш. Так что я не знаю, почему это не предусмотрено. Учитывая copy_if
фиаско Я не уверен, что есть много смысла предполагать, что всегда есть веские причины для недоступных алгоритмов:-)
Так как ваш T
является указателем, вы также можете сохранить копию указателя в объекте функции.
Кроме этого, так все и делается, и тут не так много.
Кроме того, не стоит хранить голые указатели в контейнере, если только вы не очень осторожны с обеспечением безопасности исключений, что почти всегда доставляет больше хлопот, чем оно того стоит.
Это именно то, что find_if
для - он принимает предикат, который вызывается для сравнения элементов.