пятница, 13 мая 2011 г.

sum of pairs

Вы когда нибудь пробовали получить сумму элементов контейнера, который хранит элементы типа std::pair? Если да, то вы заметили, что std::pair не определяет operator+. На помощь приходит новый стандарт, в котором пишем лямбда-функцию, или библиотека boost::lambda с которой получаем следующий прекрасный но сложноперевариваемый код:
#include <deque>

#include <boost/lambda/bind.hpp>
#include <boost/lambda/construct.hpp>

template<typename T>
void summarize()
{
    typedef std::pair<T, T> pt_t;
    std::deque<pt_t> xs;
    using namespace boost::lambda;

    // fill xs with stuff

    pt_t res = std::accumulate(
        xs.begin(), xs.end(), std::make_pair(T(),T()),
        bind( constructor<pt_t>(),
             bind( std::plus<T>(), bind(&pt_t::first,_1), bind(&pt_t::first,_2) ),
             bind( std::plus<T>(), bind(&pt_t::second,_1), bind(&pt_t::second,_2) )
             )
         );

}

9 комментариев:

  1. Недавно интереса ради писал свой итератор, который при разыменовании возвращал определенное поле структуры. Так называемый, field_iterator. Выглядит попроще лямбды... В данном случае это, конечно, не поможет...

    ОтветитьУдалить
  2. Этот комментарий был удален автором.

    ОтветитьУдалить
  3. А не проще ли было определить этот самый оператор?

    template<typename T1, typename T2>
    std::pair<T1,T2> operator + (const std::pair<T1,T2> & p1, const std::pair<T1,T2> & p2)
    {
    return std::make_pair(p1.first + p2.first, p1.second + p2.second);
    }

    Правда при этом порождается новая сущность, что не очень гуд...

    ОтветитьУдалить
  4. Оператор придется определять в пространстве имен std иначе он не найдется, но добавлять в std свои операторы — вот это не очень гуд. Насчет новой сущности, можно передать функтор в std::accumulate.

    ОтветитьУдалить
  5. Если уж зашла речь о C++11-лямбдах, то вариант с их использованием будет выглядеть примерно так:

    int main()
    {
    typedef std::pair elem_t;
    typedef std::vector vector_t;

    vector_t vec = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};

    auto result = std::accumulate(vec.begin(), vec.end(), elem_t{0, 0},
    [](elem_t const& result, elem_t const& elem) -> elem_t {return {result.first + elem.first, result.second + elem.second};});

    std::cout << "{" << result.first << ", " << result.second << "}" << std::endl;
    }

    Только вариант с range-based for, как мне кажется, выглядит проще:

    int main()
    {
    typedef std::pair elem_t;
    typedef std::vector vector_t;

    vector_t vec = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};

    elem_t result = {0, 0};
    for (auto e : vec)
    result = {result.first + e.first, result.second + e.second};

    std::cout << "{" << result.first << ", " << result.second << "}" << std::endl;
    }

    Отдельная интересная задача - это генерализировать сумматор до произвольного кортежа (а не только для пар).

    ОтветитьУдалить
  6. Раз уж речь зашла о C++11 и лямбдах, сейчас работаю над библиотекой LINQ для C++: http://code.google.com/p/boolinq/

    ОтветитьУдалить
  7. Хотелось бы провести Code-Review... Вроде на гуглокоде присутствует такая возможность. Может кто подскажет что при этом надо делать... Ни разу не учавствовал в автоматизированных обзорах кода... Может кто хочет принять участие или хотя бы посоветовать?

    ОтветитьУдалить
  8. Было бы интересно гуглувсий встроенный движок для ревью посмотреть, ранее только CodeCollaborator и ReviewBoard использовал. Так что зовите на ревью если что.

    ОтветитьУдалить
  9. Раз уж речь зашла о C++11 и лямбдах, сейчас работаю над библиотекой LINQ для C++: http://code.google.com/p/boolinq/

    Интересная фишка. Тоже в своё время на этот счёт думал, даже где-то наброски кода были. В итоге "выстрелило" не Linq-подобный синтаксис, а ленивые списки:
    https://bitbucket.org/FlexFerrum/flexferrum_lib/src/fa7dd2bfb6d6/tests/lazy_list/lazy_list.cpp

    Это несколько альтернативный взгляд на похожий функционал. С одной стороны, не поддерживает такие фишки, как sort, countof и т. п., с другой - позволяет удобно работать с произвольными последовательностями, не накладывая на них лишних ограничений. В том числе, генерировать бесконечные последовательности (например, числа Фибоначчи).

    ОтветитьУдалить