[SOLVED][C++ boost] Доступ к членам лямбда-аргументов.
Можно заюзать c++0x:
std::vector<S> v;
v.push_backS){7});
v.push_backS){12});
v.push_backS){1});
v.push_backS){13});
std::sort(v.begin v.end [](S a, S b){return a.p < b.p; });
std::for_each(v.begin v.end [](S a){std::cout << a.p << std::endl;});
std::sort
(
v.begin
v.end
boost::bind
(
std::less<int>
boost::bind(&S::p, _1
boost::bind(&S::p, _2)
)
);
std::sort
(
v.begin
v.end
boost::bind(&S::p, _1) < boost::bind(&S::p, _2)
);
На лямбде получится тоже самое, только там байнд и плейсхолдеры будут из лямбды
Что приобретается от таких замороченных конструкций?
Ух ты, не знал, что байнд такое умеет. Попробую завтра на работе.
2
Представь, что у меня есть приватный метод класса, которому нужно что-то по-быстрому отсортировать. Совершенно не хочется только ради него заводить функцию-сравнение, равно как и писать внешний функтор. Кроме того это сильно упрощенных пример. На самом деле в разных местах эта структура сортируется по разным признакам. Лично мне так очень часто не хватает в старом добром С++ просто локальных функций, не говоря уже о лямбдах. Так и не понял до сих пор, чего они им не угодили?
Лично мне так очень часто не хватает в старом добром С++ просто локальных функций, не говоря уже о лямбдах.Ну на худой конец можно функтор прямо в методе объявить — как-то так:
struct S
{
int p;
};
class L
{
private:
std::vector<S> v;
void sortThis
{
struct Compare
{
bool operator (S a, S b) { return a.p < b.p; }
} cmp;
std::sort(v.begin v.end cmp);
}
public:
L
{
v.push_backS){7});
v.push_backS){12});
v.push_backS){1});
v.push_backS){13});
sortThis;
}
void print
{
std::for_each(v.begin v.end [](S a){std::cout << a.p << std::endl;});
}
};
int main
{
L l;
l.print;
}
По крайней мере gcc и clang(за исключением лямбды, ее надо так же переписать) это хавают, не помню, разрешает ли стандарт.
Что приобретается от таких замороченных конструкций?По-моему, не особо замороченнее, чем обычный оператор, зато гораздо короче
Лично мне так очень часто не хватает в старом добром С++ просто локальных функций, не говоря уже о лямбдах. Так и не понял до сих пор, чего они им не угодили?Чем не устраивает вариант обычной статической функции? "Не хочется" — плохой ответ, ибо моём случае текст будет читабельный, а в твоём — достаточно сложная и вытянутая конструкция.
По-моему, не особо замороченнее, чем обычный оператор, зато гораздо короче
правда ты считаешь, что это читабельно? А если в струттуре 5 полей, и для сортировки они имеют разную значимость?[](S a, S b){return a.p < b.p; }
А чем это менее читабельно, чем отдельное определение оператора сравнения? Тоже самое только определено ближе к месту использования
я сам люблю краткий код, но тут явно код не краткий, а скорее самобытный.
Наверное, нужно просто привыкнуть к такому синтаксису (если я правильно тебя понял). Мне сначала синтаксис лямбд казался убогим, а потом привык и ниче теперь - если компилятор позволяет, использую
По крайней мере gcc и clang(за исключением лямбды, ее надо так же переписать) это хавают, не помню, разрешает ли стандарт.по стандарту локальные классы нельзя передавать в шаблоны
boost::bind(&S::p, _1) < boost::bind(&S::p, _2)А объясни, пожалуйста, как это работает, я с бустом плохо знаком.
Мне приходит в голову, что сначала буст как-то создаёт два неких функтора F(a) и F(..., b а затем у нас работает некий operator < (F x, F y который как-то хитро возвращает новый функтор G(a, b). Но как-то это очень хитро и странно, и я подозреваю, что всё не так.
по стандарту локальные классы нельзя передавать в шаблоныТо есть, это самодеятельность компилятора, ясно, спасибо
Представь, что у меня есть приватный метод класса, которому нужно что-то по-быстрому отсортировать. Совершенно не хочется только ради него заводить функцию-сравнение, равно как и писать внешний функтор. Кроме того это сильно упрощенных пример. На самом деле в разных местах эта структура сортируется по разным признакам. Лично мне так очень часто не хватает в старом добром С++ просто локальных функций, не говоря уже о лямбдах. Так и не понял до сих пор, чего они им не угодили?
Чем не устраивает вариант обычной статической функции? "Не хочется" — плохой ответ, ибо моём случае текст будет читабельный, а в твоём — достаточно сложная и вытянутая конструкция.Не хочется, потому что это нарушает принцип инкапсуляции.
sort(v.begin v.end (&_1)->*(&S::p;
sort(v.begin v.end (&_1)->*(&S::p) < (&_2)->*(&S::p;
ах да, забыл сказать - гори ваш boost в аду за такое!
нужно просто привыкнуть к такому синтаксисуесли так рассуждать, то можно все программы в одну строчку написать, а потом
привыкнуть к такому синтаксису
boost::bind(&S::p, _1) < boost::bind(&S::p, _2)Вообще, то, что это работает, проверить просто:
А объясни, пожалуйста, как это работает, я с бустом плохо знаком.
Мне приходит в голову, что сначала буст как-то создаёт два неких функтора F(a) и F(..., b а затем у нас работает некий operator < (F x, F y который как-то хитро возвращает новый функтор G(a, b). Но как-то это очень хитро и странно, и я подозреваю, что всё не так.
struct S
{
S(int p_) : p(p_) {}
int p;
};
int wmain(int argc, wchar_t* argv[])
{
std::vector<S> v;
v.push_back(S(5;
v.push_back(S(1;
v.push_back(S(-10;
v.push_back(S(15;
std::sort(v.begin v.end boost::bind(&S::p, _1) < boost::bind(&S::p, _2;
std::transform(v.begin v.end std::ostream_iterator<int>(cout, ", " boost::bind(&S::p, _1;
std::cout << std::endl;
return 0;
}
-10, 1, 5, 15,
Press any key to continue . . .
Хитрого там ничего нет. Я потому и написал изначально два варианта, чтобы можно было увидеть, как можно перегрузить оператор. Пруф линк
Я прочитал с интересом, но не понял, а чем плохо просто статическую функцию сравнения написать?На этот раз соглашусь с тобой: хоть иногда и хочется написать что-то покороче да попроще, но потом, чтобы преемникам твоего кода это понять, им придется разбираться в boost::bind, в лямбдах и прочих прелестях, теряя кучу времени и нервов, хотя ты мог бы написать явно и понятно лишние три строчки.
Что приобретается от таких замороченных конструкций?
придется разбираться в boost::bind, в лямбдахРазбираться в лямбдах - это да, тяжелый квест, и только потомки древних лемурийцев способны отправиться в это полное ОПАСНОСТЕ путешествие.
хоть иногда и хочется написать что-то покороче да попроще, но потом, чтобы преемникам твоего кода это понять, им придется разбираться в boost::bind, в лямбдах и прочих прелестях, теряя кучу времени и нервов, хотя ты мог бы написать явно и понятно лишние три строчки.К сожалению, трех строчек в этом случае будет недостаточно. Если писать развернутый функтор с параметрами для конструктора и не вытягивать его в одну строку, то все 10. И дело даже не в трех строчках, а в необходимости создания внешней сущности, что приводит к нарушению принципа инкапсуляции! Ну как объект виноват в том, что мне нужно что-то с ним сделать? Это мои локальные потребности, которые должны требовать чисто локальных манипуляций.
По поводу приемников: напиши коммент. Типа сортируем здесь по такому признаку. Если им нужно будет что-то поменять, могут сделать по-своему, без буста, т.к. коммент объясняет, что происходит.
им придется разбираться в boost::bind, в лямбдах и прочих прелестяхНу вообще, boost::bind - принят в 0x, поэтому любой уважающий себя С++'р должен его изучить. Если же человек, который занимается якобы "разработкой на С++", просто прочитал одного Кернигана и не хочет ничего больше изучать, то, блин, нех ему делать в программировании на С++, пусть в Си идет (дофига проектов на Си написано) или в еще какой-нить язык, где достаточно 10-ти страниц прочитать, чтобы весь язык освоить
Если писать развернутый функтор с параметрами для конструктора и не вытягивать его в одну строку, то все 10. И дело даже не в трех строчках, а в необходимости создания внешней сущности, что приводит к нарушению принципа инкапсуляции!Я не понимаю, как ты собрался одно сравнение вытянуть в 10 строк? Использование boost::bind, которое есть в данной теме, эквивалентно следующей записи:
bool compare(const S& s1, const S& s2)
{
return s1.p < s2.p;
}
При чём тут инкапсуляция!11!
или в еще какой-нить язык, где достаточно 10-ти страниц прочитать, чтобы весь язык освоитьтут есть еще проблема яблока от яблони, про которую нужно не забывать.
вот, к примеру, многие ли из любителей лямбд найдут ошибку в следующем коде:
#include <stdio.h>
int func(int arg)
{
switch (arg)
{
case 0:
printf("case 0: 0 == %d\n", arg);
return 0;
defau1t:
printf("default: 0 != %d\n", arg);
return 0;
}
printf("bad case :)\n");
return -1;
}
int main(int argc, char **argv)
{
func(0);
func(1);
return 0;
}
не страшно ли уважаемым гордонам фрименам сидеть со своими лямбдами (из буста) на столь зыбком фундаменте?
не страшно ли им заниматься синтаксическими извращениями, когда даже в 10-тистраничном стандарте
возможен такой феерический пиздец.
кто нашел ошибку быстро, не пишите.
мне кажется, ее поиск - это очень важный экспириенс.
Бачан, жжошь. Нашел, только когда собрал, запустил, охуел, открыл в редакторе и посмотрел внимательно.
он правда сантехник, так что больше по джаве щас вроде, а так - большой юморист, ага.
Ну вообще, boost::bind - принят в 0x, поэтому любой уважающий себя С++'р должен его изучить. Если же человек, который занимается якобы "разработкой на С++", просто прочитал одного Кернигана и не хочет ничего больше изучать, то, блин, нех ему делать в программировании на С++, пусть в Си идет (дофига проектов на Си написано) или в еще какой-нить язык, где достаточно 10-ти страниц прочитать, чтобы весь язык освоитьЧто касается моего мнения, то я считаю, что язык и его библиотеки лежат в двух разных плоскостях. Первое - возможности. Второе - реализованные возможности. Ориентироваться на второе неправильно.
зы
давно считаю, что стандартизаторов C++ надо всех скопом посадить на кол. такой мощный язык поганят всякой херотенью, причем обычно с обоснованием, что мол так было принято писать в старину при царе горохе, поэтому в будущем так тоже должно быть можно писать.
такое действительно должно компилится по стандарту?ну оно по презумпции разрешенности, я так понимаю, компилится.
нафига им(стандартизаторам) такое понадобилось?
его нужно было специально запретить, но стандарты ж принимаются серьезными людьми.
там не додумались до такого, вот и живем.
самое стремное, что даже с -Wextra всякими оно выдает только один странный ворнинг "defined but not used".
я с тех пор к таким ворнингам отношусь серьезно.
вообще у ван дер линдена много и очень по делу про C-стандарт
сказано в его книге "Expert C Programming. Deep C Secrets".
я даже предположу, что он там перечислил *все* недостатки языка C,
что само по себе уже неплохо, т.к. есть шанс, что их количество конечно.
давно считаю, что стандартизаторов C++ надо всех скопом посадить на кол. такой мощный язык поганят всякой херотенью, причем обычно с обоснованием, что мол так было принято писать в старину при царе горохе, поэтому в будущем так тоже должно быть можно писать.да, жаль C++, такой язык мог бы быть заебательский!
Вообще, то, что это работает, проверить простоНет, я ни на секунду не сомневаюсь, что это работает
Мне интересно, как именно это устроено.
ну оно по презумпции разрешенности, я так понимаю, компилится.Ошибку я нашёл после того, как не нашёл использование lambda. Зря ты про неё написал, это заставило внимательно прочитать код. А он что, компилируется?
я долго думал, что лучше - спрятать ошибку посильнее, или наоборот - блиц-холивар.
в итоге плюнул и запостил как на душу легло.
goto чтоль ни разу не писал?Ээээ.... нет.
до меня дошло только после твоего ответа mike-у, что компилятор думает, что это название метки, и поэтому это хавает.
спасает еще то, что на qwerty-клавиатуре "1" и "l" спутать довольно трудно.
если, конечно, не делать этого специально.
мой (удаленный) ответ майку:
короче, это же просто метка. компилятор не может ничего против сказать, т.к. с т.з. языка все по-честному
и вот лишь одна странность - метка не используется (т.е. нигде нет строчки "goto defau1t;"). =)
спасает еще то, что на qwerty-клавиатуре "1" и "l" спутать довольно трудно.
Ещё ide подсвечивает.
Ещё ide подсвечивает.Ты что, true Си-шный код можно редактировать только под vi.
Я копипастил в vim. Бага спалилась сразу же по отступам.
Нет, я ни на секунду не сомневаюсь, что это работаетЧерез шаблоны. Вот очень приблизительная механика. (Наверняка где-то не по стандарту, сделал на скорую руку в MSVC 10.0)
Мне интересно, как именно это устроено.
template<class C, class V, int N>
class bound_field
{
public:
static const int _N = N;
bound_field(V (C::*pv : m_pv(pv)
{
}
const V& operatorconst C& c) const
{
return c.*m_pv;
}
private:
const V (C::* m_pv);
};
template<int N1, int N2>
struct resolve_less
{
};
template<>
struct resolve_less<1, 2>
{
template<class V>
bool operatorconst V& v1, const V& v2)
{
return v1 < v2;
}
};
template<>
struct resolve_less<2, 1>
{
template<class V>
bool operatorconst V& v1, const V& v2)
{
return v2 < v1;
}
};
template<class F1, class F2, int N1 = F1::_N, int N2 = F2::_N>
class less_func
{
public:
less_func(const F1& f1, const F2& f2) : m_f1(f1 m_f2(f2)
{
}
template<class C>
bool operatorconst C& c1, const C& c2)
{
return resolve_less<N1, N2>m_f1(c1 m_f2(c2;
}
private:
const F1 m_f1;
const F2 m_f2;
};
template<class C, class V, int N1, int N2>
less_func<bound_field<C, V, N1>, bound_field<C, V, N2>> operator<(const bound_field<C, V, N1>& b1, const bound_field<C, V, N2>& b2)
{
return less_func<bound_field<C, V, N1>, bound_field<C, V, N2>>(b1, b2);
}
struct S
{
S(int p) : m_p(p)
{
}
int m_p;
};
int main(int argc, char* argv[])
{
bound_field<S, int, 1> b1(&S::m_p);
bound_field<S, int, 2> b2(&S::m_p);
S s1(5);
S s2(7);
std::cout << b1 < b2s1, s2) ? "true" : "false") << std::endl;
std::cout << b1 < b2s2, s1) ? "true" : "false") << std::endl;
std::cout << b2 < b1s1, s2) ? "true" : "false") << std::endl;
std::cout << b2 < b1s2, s1) ? "true" : "false") << std::endl;
return 0;
}
Ещё ide подсвечивает.метки обычно тем же цветом, что и case-конструкции подсвечены.
по крайней мере во всех IDE, что использовал я, было так.
Я копипастил в vim. Бага спалилась сразу же по отступам.поясни.
и у кого после этого шрифты говно?
я хотел что-нибудь еденькое приписать про шрифты, ага.
вообще, ты мои шрифты хвалил когда-то, я всем хвастался потом.
зато мои все ругали
помню, как в далеком сентябре 2002-го зашел к тебе подключить интернет за 50 рублей.
чорный десктоп играл какой-то дет-, дес- или деф-метал, пока ты вбивал в него аццкие символы
каким-то неведомым пользователю Windows 98 Second Edition RUS шрифтом.
думаю, это был очень важный для формирования моего жизненного сценария экспириенс.
Ахтунг. Спасибо.
Ахтунг. Спасибо.Это сейчас что было?
поясни.Оп!
Это сейчас что было?Это я ужаснулся конструкции и поблагодарил тебя за разъяснение
зачот. покажи вимрц.
это стандартно. херачишь это без set paste, оно едет говном, потом ты все это выделяешь и жмешь равно, чтобы автоиндент сработал. тут оно и оно. а еще надо юзать хорошие шрифты, в терминус они очень хорошо отличаются
жмешь равно, чтобы автоиндент сработалыыы. спасибо, я не пользовался им никогда.
вернее, я думал, что настройки автоиндента затрагивают те случаи,
когда вбиваешь новый код, а про кнопку <=> не знал. =)
вообще, вместо ядра лучше б чужие вимрц транслировали.
это стандартно. херачишь это без set paste, оно едет говном, потом ты все это выделяешь и жмешь равно, чтобы автоиндент сработал. тут оно и оно. а еще надо юзать хорошие шрифты, в терминус они очень хорошо отличаютсяShift + Ins - едет говном.
Щелчок по колесу мыши - вставляется оригинально.
я свой вимрц в альт.линуксе выкладывал тебе он, помнится, еще и понравился.
я свой вимрц в альт.линуксе выкладывал тебе он, помнится, еще и понравился.ага, ну они меняются (по крайней мере у меня так бывает). =)
а тут дело не в нем, как выяснилось.
макс, про >.< знаю, ага.
более отмороженной аргументации не видел...
метки обычно тем же цветом, что и case-конструкции подсвечены.
по крайней мере во всех IDE, что использовал я, было так.
Эклипс не подсветил метку.
$ cat ~/.vimrc
filetype plugin indent on
$ vim -h | head -n 1
VIM - Vi IMproved 7.2 (2008 Aug 9, compiled Sep 21 2009 11:22:49)
ну в смысле, я там выше непонятно написал про вбивание нового кода, да.
я не то имел в виду, что там написано.
Оставить комментарий
Serpent555
Хочу отсортировать v по элементу p содержащихся в нем структур. Сделать это указанным образом не удается:
Есть ли возможность решить данную задаче без описания внешнего предиката? Я бустом до этого толком не пользовался, так что призываю специалистов. Нагуглить ничего дельного не получилось.