Как к станд.:: найти использование Сравнить объекта?

Я смущен интерфейсом std::find. Почему это не берет a Compare объект, который говорит это, как сравнить два объекта?

Если я мог бы передать a 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"
6
задан Frank 16 April 2010 в 23:35
поделиться

3 ответа

find не может быть перегружен, чтобы принимать унарный предикат вместо значения, потому что это неограниченный параметр шаблона. Поэтому, если вы вызвали find (first, last, my_predicate) , возникнет потенциальная двусмысленность, хотите ли вы, чтобы предикат оценивался для каждого члена диапазона, или вы хотите найти член диапазон, равный самому предикату (это может быть диапазон предикатов, о котором знают или заботятся все разработчики стандартных библиотек, либо value_type итератора может быть преобразован как в тип предиката, так и его аргумент_типа ). Следовательно, для find_if необходимо использовать отдельное имя.

find мог быть перегружен, чтобы принять необязательный двоичный предикат в дополнение к искомому значению. Но фиксация значений в функторах, как вы это сделали, является настолько стандартной техникой, что я не думаю, что это принесет значительный выигрыш: в этом нет необходимости, поскольку вы всегда можете достичь того же результата с помощью find_if .

Если вы получили find , который вам нужен, вам все равно придется написать функтор (или использовать ускорение), поскольку не содержит ничего для разыменования указатель. Однако ваш функтор был бы немного проще, чем двоичный предикат, или вы могли бы использовать указатель на функцию, так что это было бы скромным выигрышем. Поэтому я не знаю, почему это не предусмотрено. Учитывая фиаско copy_if , я не уверен, что есть смысл предполагать, что всегда есть веские причины для недоступных алгоритмов: -)

6
ответ дан 16 December 2019 в 21:37
поделиться

Поскольку ваш T является указателем, вы также можете сохранить копию указателя в объекте функции.

Кроме этого, это то, как это делается, и не более того.

Кстати, хранить голые указатели в контейнере - не лучшая идея, если только вы не очень осторожны с обеспечением безопасности исключений, что почти всегда доставляет больше хлопот, чем оно того стоит.

2
ответ дан 16 December 2019 в 21:37
поделиться

Именно для этого и предназначен find_if - ему нужен предикат, который вызывается для сравнения элементов.

0
ответ дан 16 December 2019 в 21:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: