Почему в stl нет функции-члена for_each для каждого типа коллекции? - PullRequest
5 голосов
/ 03 сентября 2011

Например:

v.for_each([](int i) { printf("%d\n", i); }); 

, если он более элегантный и читаемый, чем обычно используемый:

std::for_each(v.begin(), v.end(), [](int i) { printf("%d\n", i); });

Существует ли законная причина, по которой такая функция-член отсутствует в стандарте?

Ответы [ 4 ]

8 голосов
/ 03 сентября 2011

Это стандартное обоснование дизайна для всей библиотеки: отделение контейнеров от алгоритмов.

Если бы вы сделали это по-своему, вам пришлось бы реализовать каждую функцию X для каждого контейнера Y, что приведет вас к реализации M * N, если у вас есть M функций и N контейнеров.

Используя итераторы и заставляя алгоритмы работать на итераторах, а не контейнерах, вам нужно только реализовать M алгоритмов плюс N интерфейсов итераторов.

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

2 голосов
/ 03 сентября 2011
template <class InputIterator, class UnaryFunction>
UnaryFunction for_each(InputIterator first, InputIterator last, UnaryFunction f);

Как вы можете видеть, for_each принимает итератор ввода как в параметре, поэтому любой контейнер stl, который может обеспечить совместимость с итератором ввода (то есть, помимо итератора ввода, он также может быть двунаправленным, итератором произвольного доступа и т. Д.), Будет совместим с std: :для каждого. Создавая этот способ, stl генерирует отдельный алгоритм от типа данных (контейнеров), который является более элегантным и универсальным.

1 голос
/ 03 сентября 2011

Простой факт заключается в том, что стандартная библиотека была построена в то время, когда язык не предлагал много функций, и многие распространенные в настоящее время проекты, такие как миксины на основе CRTP, не существовали.Это означает, что улучшенные дизайны, которые теперь очевидны, просто не могли быть реализованы или проектируемы при создании библиотеки Standard.

Итераторы создают отличную универсальную реализацию, но они создают дурацкий универсальный интерфейс.Меня огорчает, что вместо того, чтобы решить проблему с дизайном библиотеки и перестроить ее, вместо этого они представили одну особую особенность языка для одного крошечного подмножества проблемы.

0 голосов
/ 03 сентября 2011

Зачем вам это нужно?

Функции-члены служат цели, только если реализация может быть сделана более эффективной (set :: find более эффективна, чем std :: find () в наборе).

PS О, и если вы хотите избежать вездесущих вызовов .begin(), en .end(), используйте Алгоритмы повышения диапазона .Сладкий синтаксический сахар

Случайная выборка, вдохновленная примером Boost Range:

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/pending/integer_range.hpp>

using namespace boost::adaptors;

static int mod7(int v) 
    { return v % 7; }

int main() 
{
    std::vector<int> v;

    boost::copy(
            boost::make_integer_range(1,100) | transformed(mod7), 
            std::back_inserter(v));

    boost::sort(v);

    boost::copy(
            v | reversed | uniqued, 
            std::ostream_iterator<int>(std::cout, ", "));
}
...