алгоритмы std с указателем на элемент в качестве компаратора / " ключ"
Я часто ловлю себя на том, что использую std::sort
, std::max_element
, и тому подобное с лямбдой, которая просто вызывает функцию-член
std::vector<MyType> vec;
// populate...
auto m = std::max_element(std::begin(vec), std::end(vec),
[](const MyType& a, const MyType& b) { return a.val() < b.val()})
Это похоже на пустую трату символов и потерю ясности. Я знаю, что я мог бы написать другую функцию/вызываемую и передать указатель функции/вызываемый объект этим функциям алгоритма, но мне часто нужно сделать это только один раз в программе, и это не кажется мне хорошим способом решения проблемы. То, что я хочу сделать, в идеале-это скажите:
auto m = std::max_element(std::begin(vec), std::end(vec), &MyType::val);
И отсортируйте объекты по их val()
s. Есть ли какая-то часть stdlib, которую я пропускаю, которая могла бы помочь мне в этом? или другой простой способ сделать это? Я хотел бы сделать то, что это сортировка или поиск, как можно более очевидным.
&MyType::val
недостаточно, я ищу что-то, что, возможно, могло бы обернуть его или обеспечить подобную функциональность, не затуманивая смысл.4 ответа:
Вы можете использовать
std::mem_fn
(илиstd::tr1::mem_fn
)int main() { std::vector<MyType> vec; auto m = std::max_element(std::begin(vec), std::end(vec), compare_by(std::mem_fn(&MyType::field))); }
Конечно, это предполагает, что у вас есть утилита, как
compare_by
в вашем наборе инструментов (как вы должны :)):template <typename F> struct CompareBy { explicit CompareBy(F&& f) : f(std::forward<F>(f)) {} template <typename U, typename V> bool operator()(U const& u, V const& v) const { return f(u) < f(v); } private: F f; }; template <typename F> CompareBy<F> compare_by(F&& f) { return CompareBy<F>(std::forward<F>(f)); }
Смотрите жить на Колиру
Шаблонный компаратор может помочь вам:
template <typename StructureType, typename MemberType, MemberType StructureType::*member> bool comparator(const StructureType& the_first, const StructureType& the_second) { return the_first.*member < the_second.*member; }
Немного магии черт типа, безусловно, позволит вам избежать написания типа.
Как насчет однократной перегрузки
operator<
для вашего пользовательского типа? Это может быть естественно сделано внутри класса (или непосредственно рядом с ним), и тогда никакие дополнительные аргументы не требуются рядом с итераторами.Передача функции
val()
невозможна, так как необходимо передать двоичный оператор.EDIT: прочитав другие ценные альтернативы (также хороший ответ sehe), я хочу подтвердить то, что я уже упоминал в комментарии ниже: по моему мнению, ничто не сравнится с удобочитаемостью, локальностью а также гибкость лямбда-выражения (--на риск написания некоторых отрывков дважды).
@Ryan Haining: я предлагаю вам сохранить его, как в вашем первоначальном посте.