Что из следующего вам кажется более читабельным? Рукописный цикл:
for (std::vector<Foo>::const_iterator it = vec.begin(); it != vec.end(); ++it)
{
bar.process(*it);
}
Или вызов алгоритма:
#include <algorithm>
#include <functional>
std::for_each(vec.begin(), vec.end(),
std::bind1st(std::mem_fun_ref(&Bar::process), bar));
Интересно, std::for_each
действительно ли это того стоит, учитывая, что такой простой пример уже требует так много кода.
Что вы думаете об этом?
c++
algorithms
fredoverflow
источник
источник
map(bar.process, vec)
хотя карта для побочных эффектов не рекомендуется, и списочные выражения / выражения генератора рекомендуются над картой).BOOST_FOREACH
...Ответы:
Есть причина, по которой были введены лямбды, и это потому, что даже Стандартный комитет признает, что вторая форма - отстой. Используйте первую форму, пока не получите поддержку C ++ 0x и лямбда-выражений.
источник
Всегда используйте вариант, который лучше всего описывает то, что вы собираетесь делать. Это
Теперь давайте рассмотрим примеры:
У нас
for_each
там тоже есть - ура . У нас есть[begin; end)
диапазон, на котором мы хотим работать.В принципе, алгоритм был намного более явным и поэтому предпочтительным по сравнению с любой рукописной реализацией. Но тогда ... Биндеры? Memfun? В основном C ++ interna о том, как заполучить функцию-член? Для моей задачи я не забочусь о них! Я также не хочу страдать от этого многословного, жуткого синтаксиса.
Теперь другая возможность:
Конечно, это обычный шаблон для распознавания, но ... создание итераторов, зацикливание, увеличение, разыменование. Это тоже все, что меня не волнует , чтобы выполнить мою задачу.
Следует признать, что это выглядит waay лучше , чем первое решение (по крайней мере, контур тела является гибким и достаточно четко), но все же, это на самом деле не что большой. Мы будем использовать этот, если у нас не было лучшей возможности, но, возможно, у нас есть ...
Лучше?
Теперь вернемся к
for_each
. Разве не было бы здорово буквально сказатьfor_each
и быть гибким в операции, которая должна быть выполнена тоже? К счастью, начиная с C ++ 0x лямбды, мыТеперь, когда мы нашли абстрактное, общее решение для многих связанных ситуаций, стоит отметить, что в данном конкретном случае существует абсолютный фаворит №1 :
Это действительно не может быть намного яснее, чем это. К счастью, в C ++ 0x get встроен похожий синтаксис !
источник
for (const Foo& x : vec) bar.process(x);
используется или используется,const auto&
если хотите.const auto&
возможно? Не знал этого - отличная информация!Потому что это так нечитабельно?
источник
int
с иsize_t
опасно. Кроме того, индексация не работает, например, с каждым контейнеромstd::set
.В общем, первая форма читаема практически любым, кто знает, что такое цикл for, независимо от того, какой у них фон.
Кроме того, в общем, второй не настолько удобен для чтения: достаточно просто понять, что делает for_each, но если вы никогда не видели,
std::bind1st(std::mem_fun_ref
я могу представить, что это трудно понять.источник
На самом деле, даже с C ++ 0x, я не уверен,
for_each
что получит много любви.Это способ более читабельным.
Единственное, что мне не нравится в алгоритмах (в C ++) - это их аргументация на итераторах, что делает их очень многословными.
источник
Если бы вы написали bar как функтор, было бы намного проще:
Здесь код вполне читабелен.
источник
Я предпочитаю последнее, потому что это аккуратно и чисто. На самом деле это часть многих других языков, но в C ++ это часть библиотеки. Это не очень важно.
источник
Теперь эта проблема на самом деле не относится к C ++, я бы сказал.
Дело в том, что передача некоторого функтора в еще одну функцию не предназначена для замены циклов .
Предполагается, что он упрощает определенные шаблоны, которые становятся очень естественными для функционального программирования, такие как посетитель и наблюдатель , просто чтобы назвать два, которые сразу приходят мне в голову.
В языках, в которых отсутствуют функции первого порядка (вероятно, Java является лучшим примером), такие подходы всегда требуют реализации некоторого заданного интерфейса, который является довольно многословным и избыточным.
Обычное использование, которое я вижу много на других языках:
Преимущество этого в том, что вам не нужно знать, как
someCollection
на самом деле реализовано или чтоsomeUnaryFunctor
делает. Все, что вам нужно знать, это то, что егоforEach
метод будет перебирать все элементы коллекции, передавая их данной функции.Лично, если вы находитесь в положении, чтобы иметь всю информацию о структуре данных, которую вы хотите перебрать, и всю информацию о том, что вы хотите сделать на каждом шаге итерации, то функциональный подход слишком усложняет вещи, особенно в языке, где это, видимо, довольно утомительно.
Кроме того, вы должны иметь в виду, что функциональный подход медленнее, потому что у вас много вызовов, которые приходят с определенной стоимостью, которых у вас нет в цикле for.
источник
std::for_each(vec.begin(), vec.end(), std::bind1st(std::mem_fun_ref(&Bar::process), bar));
И это либо медленнее во время выполнения или компиляции (если вам повезет). Я не понимаю, почему замена структур управления потоками вызовами функций делает код лучше. О любой представленной здесь альтернативе более читабельно.Я думаю, что проблема здесь в том, что на
for_each
самом деле это не алгоритм, а просто другой (и, как правило, плохой способ) писать рукописный цикл. с этой точки зрения это должен быть наименее используемый стандартный алгоритм, и да, вы, вероятно, могли бы также использовать цикл for. однако рекомендация в названии остается в силе, поскольку есть несколько стандартных алгоритмов, адаптированных для более конкретного использования.Там, где есть алгоритм, который более точно выполняет то, что вы хотите, тогда да, вы должны отдавать предпочтение алгоритмам над рукописными циклами. очевидными примерами здесь являются сортировка с использованием
sort
илиstable_sort
или поиск с помощьюlower_bound
,upper_bound
илиequal_range
, но большинство из них имеют некоторую ситуацию, в которой их предпочтительнее использовать, чем цикл с ручным кодированием.источник
Для этого небольшого фрагмента кода оба одинаково читабельны для меня. В целом, я считаю, что ручные циклы подвержены ошибкам и предпочитаю использовать алгоритмы, но это действительно зависит от конкретной ситуации.
источник