#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) )
)
);
}
▼
пятница, 13 мая 2011 г.
sum of pairs
Вы когда нибудь пробовали получить сумму элементов контейнера, который хранит элементы типа std::pair? Если да, то вы заметили, что std::pair не определяет operator+. На помощь приходит новый стандарт, в котором пишем лямбда-функцию, или библиотека boost::lambda с которой получаем следующий прекрасный но сложноперевариваемый код:
Недавно интереса ради писал свой итератор, который при разыменовании возвращал определенное поле структуры. Так называемый, field_iterator. Выглядит попроще лямбды... В данном случае это, конечно, не поможет...
ОтветитьУдалитьЭтот комментарий был удален автором.
ОтветитьУдалитьА не проще ли было определить этот самый оператор?
ОтветитьУдалить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);
}
Правда при этом порождается новая сущность, что не очень гуд...
Оператор придется определять в пространстве имен std иначе он не найдется, но добавлять в std свои операторы — вот это не очень гуд. Насчет новой сущности, можно передать функтор в std::accumulate.
ОтветитьУдалитьЕсли уж зашла речь о 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;
}
Отдельная интересная задача - это генерализировать сумматор до произвольного кортежа (а не только для пар).
Раз уж речь зашла о C++11 и лямбдах, сейчас работаю над библиотекой LINQ для C++: http://code.google.com/p/boolinq/
ОтветитьУдалитьХотелось бы провести Code-Review... Вроде на гуглокоде присутствует такая возможность. Может кто подскажет что при этом надо делать... Ни разу не учавствовал в автоматизированных обзорах кода... Может кто хочет принять участие или хотя бы посоветовать?
ОтветитьУдалитьБыло бы интересно гуглувсий встроенный движок для ревью посмотреть, ранее только CodeCollaborator и ReviewBoard использовал. Так что зовите на ревью если что.
ОтветитьУдалитьРаз уж речь зашла о 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 и т. п., с другой - позволяет удобно работать с произвольными последовательностями, не накладывая на них лишних ограничений. В том числе, генерировать бесконечные последовательности (например, числа Фибоначчи).