Я смущен интерфейсом 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"
find
не может быть перегружен, чтобы принимать унарный предикат вместо значения, потому что это неограниченный параметр шаблона. Поэтому, если вы вызвали find (first, last, my_predicate)
, возникнет потенциальная двусмысленность, хотите ли вы, чтобы предикат оценивался для каждого члена диапазона, или вы хотите найти член диапазон, равный самому предикату (это может быть диапазон предикатов, о котором знают или заботятся все разработчики стандартных библиотек, либо value_type
итератора может быть преобразован как в тип предиката, так и его аргумент_типа
). Следовательно, для find_if
необходимо использовать отдельное имя.
find
мог быть перегружен, чтобы принять необязательный двоичный предикат в дополнение к искомому значению. Но фиксация значений в функторах, как вы это сделали, является настолько стандартной техникой, что я не думаю, что это принесет значительный выигрыш: в этом нет необходимости, поскольку вы всегда можете достичь того же результата с помощью find_if
.
Если вы получили find
, который вам нужен, вам все равно придется написать функтор (или использовать ускорение), поскольку
не содержит ничего для разыменования указатель. Однако ваш функтор был бы немного проще, чем двоичный предикат, или вы могли бы использовать указатель на функцию, так что это было бы скромным выигрышем. Поэтому я не знаю, почему это не предусмотрено. Учитывая фиаско copy_if
, я не уверен, что есть смысл предполагать, что всегда есть веские причины для недоступных алгоритмов: -)
Поскольку ваш T
является указателем, вы также можете сохранить копию указателя в объекте функции.
Кроме этого, это то, как это делается, и не более того.
Кстати, хранить голые указатели в контейнере - не лучшая идея, если только вы не очень осторожны с обеспечением безопасности исключений, что почти всегда доставляет больше хлопот, чем оно того стоит.
Именно для этого и предназначен find_if
- ему нужен предикат, который вызывается для сравнения элементов.