Цель то была доказать тезис о том, что С++ настолько крут, что в нем все можно сделать в бибилотеке... и лямбду, и замыкание, и черта лысого.
Насчет черта лысого не уверен, но лямбда удалась на славу:
void MyF1(vector<int>& vec, int s)
{
transform(vec.begin(), vec.end(), vec.begin(), (s + _1));
}
VC8.0 -O2
?MyF1@@YAXAAV?$vector@HV?$allocator@H@std@@@std@@H@Z PROC ; MyF1, COMDAT
mov eax, DWORD PTR _vec$[esp-4]
mov ecx, DWORD PTR [eax+4]
mov edx, DWORD PTR [eax+8]
mov eax, ecx
cmp eax, edx
push esi
push edi
je SHORT $LN71@MyF1
mov esi, DWORD PTR _s$[esp+4]
$LL82@MyF1:
mov edi, DWORD PTR [eax]
add edi, esi
mov DWORD PTR [ecx], edi
add eax, 4
add ecx, 4
cmp eax, edx
jne SHORT $LL82@MyF1
$LN71@MyF1:
pop edi
pop esi
ret 0
Очень похоже на нулевые издержки.
Re[7]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Насчет черта лысого не уверен, но лямбда удалась на славу:
D>
D>void MyF1(vector<int>& vec, int s)
D>{
D> transform(vec.begin(), vec.end(), vec.begin(), (s + _1));
D>}
D>
Вот скажи мне на сколько часто тебе нужны такая лямюбда? Мне нужно как минимум обратится к челену класса, а с этим уже все не так красиво... А если нужно както так Obj.Prop1.Prop2.Prop3 то вобще тушите свет.
Короче для людей которые использовали нормальную лямбду очевидно что boost::lambda непригодно для реальной работы.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: BOOST, .NET, String.Split и производительность…
Здравствуйте, WolfHound, Вы писали:
WH>Вот скажи мне на сколько часто тебе нужны такая лямюбда? Мне нужно как минимум обратится к челену класса, а с этим уже все не так красиво... А если нужно както так Obj.Prop1.Prop2.Prop3 то вобще тушите свет. WH>Короче для людей которые использовали нормальную лямбду очевидно что boost::lambda непригодно для реальной работы.
Собственно говоря boost::lambda предназначен для того, чтобы не приходилось писать функции/функторы под простейшие случаи. Немогу не согласится, что для Obj.Prop1.Prop2.Prop3 это просто не пригодно. Вообщем более 'толстые' лямбды я все равно не пишу, предпочитаю функторы, т.к. это более декомпозиционно.
C># g++ test_with_vector.cpp C># ./a.out C>res is/ 5000000,3117 ms elapsed
C># g++ -O3 test_with_vector.cpp C># ./a.out C>res is/ 5000000,756 ms elapsed
C># g++ test_with_deque.cpp C># ./a.out C>res is 5000000,2919 ms elapsed
C># g++ -O3 test_with_deque.cpp C># ./a.out C>res is 5000000,801 ms elapsed
C># g++ test_with_list.cpp C># ./a.out C>res is 5000000,2673 ms elapsed
C># g++ -O3 test_with_list.cpp C># ./a.out C>res is 5000000,653 ms elapsed
C># python test.py C>res is 5000000, 2.100000 sec elapsed
Перед всеми извиняюсь, ляпнул.
#include <list>
#include <string>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#define OS_POSIX
#ifdef OS_WINDOWS
#include <windows.h> // for GetTickCount#else// posix#include <sys/times.h>
#endif
using namespace std;
using namespace boost::algorithm;
int main()
{
#ifdef OS_WINDOWS
DWORD start = GetTickCount();
#else
struct tms t;
long ts = sysconf(_SC_CLK_TCK);
double start = ((double) times(&t) / ts) * 1000;
#endif
int res = 0;
for(int i = 0; i < 1000000; i++)
{
list<string> tokens;
split(tokens, "123 345 asdf 23453 asdfas", is_any_of(" "));
res += tokens.size();
}
#ifdef OS_WINDOWS
DWORD stop = GetTickCount();
#else
double stop = ((double) times(&t) / ts) * 1000;
#endif
cout << "res is " << res << ',' << stop - start << " ms elapsed\n";
return 0;
}
Так как функция sysconf(_SC_CLK_TCK) (количество тиков в секунду) на моей машине возвращает 100, достаточно каждый из вышеприведённых результатов умножить на 10.
C># g++ test_with_vector.cpp C># ./a.out C>res is/ 5000000,31170 ms elapsed
C># g++ -O3 test_with_vector.cpp C># ./a.out C>res is/ 5000000,7560 ms elapsed
C># g++ test_with_deque.cpp C># ./a.out C>res is 5000000,29190 ms elapsed
C># g++ -O3 test_with_deque.cpp C># ./a.out C>res is 5000000,8010 ms elapsed
C># g++ test_with_list.cpp C># ./a.out C>res is 5000000,26730 ms elapsed
C># g++ -O3 test_with_list.cpp C># ./a.out C>res is 5000000,6530 ms elapsed
То есть лучший результат 6,530 сек.
Re[9]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Собственно говоря boost::lambda предназначен для того, чтобы не приходилось писать функции/функторы под простейшие случаи. Немогу не согласится, что для Obj.Prop1.Prop2.Prop3 это просто не пригодно. Вообщем более 'толстые' лямбды я все равно не пишу, предпочитаю функторы, т.к. это более декомпозиционно.
Что только люди не приюдумают для того чтобы оправдать использование С++.
По сравнению с нормальной лямбдой функторы не рулят совершенно.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.
Код в студию.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, WolfHound, Вы писали:
WH>>По сравнению с нормальной лямбдой функторы не рулят совершенно.
E>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.
Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.
Re[12]: BOOST, .NET, String.Split и производительность…
Здравствуйте, WolfHound, Вы писали:
E>>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера. WH>Код в студию.
Вот, пример большого функтора:
/*!
\since v.4.2.7
\brief Предикат для std::find_if.
Для очередного состояния проверяет возможность слияния
с состоянием из другого класса агентов.
Определяет, есть ли среди всех классов, на которые ссылаются
состояния, еще не полностью определенные классы.
*/class merge_possibility_checker_t
: public std::unary_function<
const state_handler_impl_ptr_vector_t::value_type &,
bool >
{
private :
/*! Список всех классов. */const class_map_t & m_all_classes;
/*! Список состояний всех классов */const std_class_relation_handler_t::class_info_map_t &
m_classes_state;
/*! Принимает значение true, если были найдены не
полностью определенные классы. */bool & m_is_incomplete_class_found;
/*! Приемник описания ошибки. */
std::string & m_error_desc;
public :
//! Основной конструктор.
merge_possibility_checker_t(
//! Список всех классов.const class_map_t & all_classes,
const std_class_relation_handler_t::class_info_map_t &
classes_state,
bool & is_incomplete_class_found,
//! Приемник описания ошибки.
std::string & error_desc )
: m_is_incomplete_class_found( is_incomplete_class_found )
, m_all_classes( all_classes )
, m_classes_state( classes_state )
, m_error_desc( error_desc )
{}
result_type
operator()( argument_type a );
private :
/*! Проверка наличия указанного состояния в указанном
классе.
\return true, если состояние найдено. */bool
try_find_state_in_class(
//! Имя искомого состояния.const std::string & state_name,
//! Класс, в котором состояние нужно найти.const class_handler_impl_t & class_handler );
};
merge_possibility_checker_t::result_type
merge_possibility_checker_t::operator()( argument_type a )
{
bool result = false;
const state_handler_impl_t::merge_list_t & merge_list =
a->merge_list();
for( state_handler_impl_t::merge_list_t::const_iterator
it = merge_list.begin(), it_end = merge_list.end();
it != it_end;
++it )
{
bool is_merge_valid = false;
const state_handler_impl_t::merge_t & m = *it;
// Должен быть известен класс.
class_map_t::const_iterator it_class = m_all_classes.find(
m.m_class_name );
if( it_class != m_all_classes.end() )
{
int state = m_classes_state.find(
m.m_class_name )->second.m_state;
// Класс должен быть полностью определен.if( std_class_relation_handler_t::state_valid == state )
{
// Должно быть известно состояние.if( try_find_state_in_class(
m.m_state_name, *( it_class->second ) ) )
// Все хорошо. Поэтому, чтобы перейти к обработке
// следующего состояния, нужно возвратить false.
is_merge_valid = true;
else
{
// Состояние не известно.
m_error_desc += std::string( "state '" ) +
a->query_name() +
"' requires merging with undefined state '" +
m.m_state_name + "' from class '" +
m.m_class_name + "';";
}
}
else if( std_class_relation_handler_t::state_invalid == state )
// Нашли ссылку на некорректный класс.
m_error_desc += std::string( "state '" ) +
a->query_name() +
"' requires merging with invalid class '" +
m.m_class_name + "';";
else
{
// Класс еще не определен.
m_is_incomplete_class_found = true;
m_error_desc += std::string( "incomplete class: " ) +
m.m_class_name + ";";
}
}
else// Нашли ссылку на неизвестный класс.
m_error_desc += std::string( "state '" ) + a->query_name() +
"' requires merging with undefined class '" +
m.m_class_name + "';";
// Если текущее слияние не корректно, то и состояние не может
// быть корректным.if( !is_merge_valid )
result = true;
}
return result;
}
bool
merge_possibility_checker_t::try_find_state_in_class(
const std::string & state_name,
const class_handler_impl_t & class_handler )
{
const state_handler_impl_ptr_vector_t & states =
class_handler.query_state_handlers();
return ( states.end() != std::find_if(
states.begin(), states.end(),
state_by_name_finder_t( state_name ) ) );
}
который используется так:
int
std_class_relation_handler_t::try_merge_states(
const class_handler_impl_t & class_handler,
const class_map_t & all_classes,
std::string & error_desc )
{
// Берем все состояния, которые нуждаются в слиянии.
state_handler_impl_ptr_vector_t states_for_merging =
class_handler.states_for_merge();
// Проверяем возможность проведения слияния.bool is_incomplete_class_found = false;
merge_possibility_checker_t checker( all_classes, m_classes,
is_incomplete_class_found, error_desc );
if( states_for_merging.end() != std::find_if(
states_for_merging.begin(), states_for_merging.end(),
checker ) )// Слияние не возможно. Осталось только определить,
// по какой причине.return ( is_incomplete_class_found ?
state_not_processed :
state_invalid );
// Выполняем слияние.
std::for_each( states_for_merging.begin(),
states_for_merging.end(),
merge_maker_t( all_classes ) );
return state_valid;
}
По поводу наследования: в своих OpenSource проектах с ходу не нашел. А код из закрытых проектов не смотрел, т.к. результат все равно не смогу показать. Но раз или два пришлось делать наследование для функторов, чтобы общую функциональность в базовый класс поместить. Ну и простейший пример наследования для функторов -- наследование от std::unary_function .
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[12]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Курилка, Вы писали:
E>>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.
К>Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.
Не очень понимаю, о чем ты. Мне просто пару раз над элементами контейнеров пришлось делать несколько похожих, но отличающихся в деталях операций (каких именно уже не помню). Поэтому я сделал базовый класс, наследник от std::unary_function, в нем пару виртуальных методов. Затем пару производных классов, в которых эти виртуальные методы перекрывались. А потом в коде вызывал std::for_each то с одним наследником, то с другим.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[13]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Курилка, Вы писали:
E>>>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.
К>>Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.
E>Не очень понимаю, о чем ты. Мне просто пару раз над элементами контейнеров пришлось делать несколько похожих, но отличающихся в деталях операций (каких именно уже не помню). Поэтому я сделал базовый класс, наследник от std::unary_function, в нем пару виртуальных методов. Затем пару производных классов, в которых эти виртуальные методы перекрывались. А потом в коде вызывал std::for_each то с одним наследником, то с другим.
О том, что если решать эту задачу с т.зр. ФП, то виртуальных методов не будет, а будет функция высшего порядка, в которую будут передаваться функции, которые соотвествуют твоим перекрытым методам.
Просто ты решал задачу в терминах объектов и тебе было так удобнее, кому-то возможно удобнее по-другому.
Re[14]: BOOST, .NET, String.Split и производительность…
Курилка wrote: > О том, что если решать эту задачу с т.зр. ФП, то виртуальных методов не > будет, а будет функция высшего порядка, в которую будут передаваться > функции, которые соотвествуют твоим перекрытым методам.
То же самое, вид сбоку.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[15]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Cyberax, Вы писали:
C>Курилка wrote: >> О том, что если решать эту задачу с т.зр. ФП, то виртуальных методов не >> будет, а будет функция высшего порядка, в которую будут передаваться >> функции, которые соотвествуют твоим перекрытым методам. C>То же самое, вид сбоку.
Не спорю, просто кому-то удобней может быть такой вид, а кому-то наоборот
Здравствуйте, Denis2005, Вы писали:
D>Насчет черта лысого не уверен, но лямбда удалась на славу:
D>
D>void MyF1(vector<int>& vec, int s)
D>{
D> transform(vec.begin(), vec.end(), vec.begin(), (s + _1));
D>}
D>
Да, уж на славу... для тех кто нормальной не видел. _1 уже круто. А возьми случаи чуть по сложнее и ты приплыл. Ведь лямбды хороши тем, что это фукнции высшего порядка которые можно комбинировать.
Да и проблем с ними не оберешся. В языках где они реализовны нормально, они имеют лексическую область видимости и их время жизни оеределяется наличием ссылок на них. Тут же фиг. А на дисерт пиколы вроде ничаянного добавления переменной с именем _1 в локальную область видимости, невнятные сообщения об ошибках и т.п.
Кстати, даже в такх, примитивных, случаях языки с полноценной поддержкой функций высшего порядка выглядят лучше.
Вот как это будет выглядить не Немерле:
transform.(s + _);
"s + _" автоматом преобразуется в лямбду с одним параметром (никаких лишних скобок и хардкодед-имен вроде "_1" не нужно). Да и отсуствие идиотизма с begin()/end() разгружает код. В итоге получается, что писать функционально конечно на С++ можно, но неудобно, не всегда быстро, и очень громоздко.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Denis2005, Вы писали:
D>Собственно говоря boost::lambda предназначен для того, чтобы не приходилось писать функции/функторы под простейшие случаи. Немогу не согласится, что для Obj.Prop1.Prop2.Prop3 это просто не пригодно. Вообщем более 'толстые' лямбды я все равно не пишу, предпочитаю функторы, т.к. это более декомпозиционно.
Для тех кто плотно попользовался функцями высшего порядка (ФВП), лямбды и локальные фукнции становятся частью средств декомпозиции кода и они начинают применяться повсеместно. Не важно насколько сложен случай. Уж обращаться к членам классов точно постоянно нужно (особенно в императивном С++).
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: BOOST, .NET, String.Split и производительность…
Здравствуйте, eao197, Вы писали:
E>Временами рулят и очень сильно. Функторы могут наследоваться. Функторы могут разрастаться до довольно таки сложной логики и приличного размера.
А что классы в других языках отменили что ли? Просто в других языках нет нужны эмулировать классами функции высшего порядка. Они уже есть в языке шататно.
И тебе ли это не знать? Снова поспорить охота?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: BOOST, .NET, String.Split и производительность…
Здравствуйте, Курилка, Вы писали:
К>Т.е. ты декомпозицию делаешь при помощи ООП? При функциональной декомпозиции это будет выглядеть иначе, наследование там вообще как понятие не существует.
Он на Руби пишет, в лучшем случае. А там как и в С++ ООП основное средство декомпозиции. Других практически нет. Одними лямбдами (блоками) сыт не будешь.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.