[SOLVED][C++ boost] Доступ к членам лямбда-аргументов.

Serpent555

  struct S
{
int p;
};

vector<S> v;

sort(v.begin v.end _1.p);

Хочу отсортировать v по элементу p содержащихся в нем структур. Сделать это указанным образом не удается:
 
For some operators, the requirements on return types prevent them to be overloaded to create lambda functors. These operators are ->., ->, new, new[], delete, delete[] and ?: (the conditional operator).

Есть ли возможность решить данную задаче без описания внешнего предиката? Я бустом до этого толком не пользовался, так что призываю специалистов. Нагуглить ничего дельного не получилось.

doublemother

//тут была фигня, поскольку я не прочитал про отсутствие внешней функции//
Можно заюзать 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;});

agent007new

На байнде вот так будет (lambda сильно круто для этого):

std::sort
(
v.begin
v.end
boost::bind
(
std::less<int>
boost::bind(&S::p, _1
boost::bind(&S::p, _2)
)
);

agent007new

Или так:
 
  
std::sort
(
v.begin
v.end
boost::bind(&S::p, _1) < boost::bind(&S::p, _2)
);


На лямбде получится тоже самое, только там байнд и плейсхолдеры будут из лямбды

Werdna

Я прочитал с интересом, но не понял, а чем плохо просто статическую функцию сравнения написать?
Что приобретается от таких замороченных конструкций?

Serpent555

2
Ух ты, не знал, что байнд такое умеет. Попробую завтра на работе.
2
Представь, что у меня есть приватный метод класса, которому нужно что-то по-быстрому отсортировать. Совершенно не хочется только ради него заводить функцию-сравнение, равно как и писать внешний функтор. Кроме того это сильно упрощенных пример. На самом деле в разных местах эта структура сортируется по разным признакам. Лично мне так очень часто не хватает в старом добром С++ просто локальных функций, не говоря уже о лямбдах. Так и не понял до сих пор, чего они им не угодили?

doublemother

Лично мне так очень часто не хватает в старом добром С++ просто локальных функций, не говоря уже о лямбдах.
Ну на худой конец можно функтор прямо в методе объявить — как-то так:
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(за исключением лямбды, ее надо так же переписать) это хавают, не помню, разрешает ли стандарт.

agent007new

Что приобретается от таких замороченных конструкций?
По-моему, не особо замороченнее, чем обычный оператор, зато гораздо короче

Werdna

Лично мне так очень часто не хватает в старом добром С++ просто локальных функций, не говоря уже о лямбдах. Так и не понял до сих пор, чего они им не угодили?
Чем не устраивает вариант обычной статической функции? "Не хочется" — плохой ответ, ибо моём случае текст будет читабельный, а в твоём — достаточно сложная и вытянутая конструкция.

Werdna

По-моему, не особо замороченнее, чем обычный оператор, зато гораздо короче

 [](S a, S b){return a.p < b.p; } 
:confused: правда ты считаешь, что это читабельно? А если в струттуре 5 полей, и для сортировки они имеют разную значимость?

agent007new

А чем это менее читабельно, чем отдельное определение оператора сравнения? Тоже самое только определено ближе к месту использования

Werdna

наверное тем же, чем 5 простых строк проще чем одна сложная.
я сам люблю краткий код, но тут явно код не краткий, а скорее самобытный.

agent007new

Наверное, нужно просто привыкнуть к такому синтаксису (если я правильно тебя понял). Мне сначала синтаксис лямбд казался убогим, а потом привык и ниче теперь - если компилятор позволяет, использую

Maurog

По крайней мере gcc и clang(за исключением лямбды, ее надо так же переписать) это хавают, не помню, разрешает ли стандарт.
по стандарту локальные классы нельзя передавать в шаблоны

doublemother

boost::bind(&S::p, _1) < boost::bind(&S::p, _2)
А объясни, пожалуйста, как это работает, я с бустом плохо знаком.
Мне приходит в голову, что сначала буст как-то создаёт два неких функтора F(a) и F(..., b а затем у нас работает некий operator < (F x, F y который как-то хитро возвращает новый функтор G(a, b). Но как-то это очень хитро и странно, и я подозреваю, что всё не так.

doublemother

по стандарту локальные классы нельзя передавать в шаблоны
То есть, это самодеятельность компилятора, ясно, спасибо :)

slonishka

Представь, что у меня есть приватный метод класса, которому нужно что-то по-быстрому отсортировать. Совершенно не хочется только ради него заводить функцию-сравнение, равно как и писать внешний функтор. Кроме того это сильно упрощенных пример. На самом деле в разных местах эта структура сортируется по разным признакам. Лично мне так очень часто не хватает в старом добром С++ просто локальных функций, не говоря уже о лямбдах. Так и не понял до сих пор, чего они им не угодили?
:lol:

Serpent555

Чем не устраивает вариант обычной статической функции? "Не хочется" — плохой ответ, ибо моём случае текст будет читабельный, а в твоём — достаточно сложная и вытянутая конструкция.
Не хочется, потому что это нарушает принцип инкапсуляции.

rosali

 sort(v.begin v.end (&_1)->*(&S::p;  

:cool:

rosali

ну или скорее уж имелось в виду
sort(v.begin v.end (&_1)->*(&S::p) < (&_2)->*(&S::p;

ах да, забыл сказать - гори ваш boost в аду за такое! :grin:

iravik

нужно просто привыкнуть к такому синтаксису
если так рассуждать, то можно все программы в одну строчку написать, а потом
привыкнуть к такому синтаксису

agent007new

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 . . .

Хитрого там ничего нет. Я потому и написал изначально два варианта, чтобы можно было увидеть, как можно перегрузить оператор. Пруф линк

erotic

Я прочитал с интересом, но не понял, а чем плохо просто статическую функцию сравнения написать?
Что приобретается от таких замороченных конструкций?
На этот раз соглашусь с тобой: хоть иногда и хочется написать что-то покороче да попроще, но потом, чтобы преемникам твоего кода это понять, им придется разбираться в boost::bind, в лямбдах и прочих прелестях, теряя кучу времени и нервов, хотя ты мог бы написать явно и понятно лишние три строчки.

apl13

придется разбираться в boost::bind, в лямбдах
Разбираться в лямбдах - это да, тяжелый квест, и только потомки древних лемурийцев способны отправиться в это полное ОПАСНОСТЕ путешествие.

Serpent555

хоть иногда и хочется написать что-то покороче да попроще, но потом, чтобы преемникам твоего кода это понять, им придется разбираться в boost::bind, в лямбдах и прочих прелестях, теряя кучу времени и нервов, хотя ты мог бы написать явно и понятно лишние три строчки.
К сожалению, трех строчек в этом случае будет недостаточно. Если писать развернутый функтор с параметрами для конструктора и не вытягивать его в одну строку, то все 10. И дело даже не в трех строчках, а в необходимости создания внешней сущности, что приводит к нарушению принципа инкапсуляции! Ну как объект виноват в том, что мне нужно что-то с ним сделать? Это мои локальные потребности, которые должны требовать чисто локальных манипуляций.
По поводу приемников: напиши коммент. Типа сортируем здесь по такому признаку. Если им нужно будет что-то поменять, могут сделать по-своему, без буста, т.к. коммент объясняет, что происходит.

agent007new

им придется разбираться в boost::bind, в лямбдах и прочих прелестях
Ну вообще, boost::bind - принят в 0x, поэтому любой уважающий себя С++'р должен его изучить. Если же человек, который занимается якобы "разработкой на С++", просто прочитал одного Кернигана и не хочет ничего больше изучать, то, блин, нех ему делать в программировании на С++, пусть в Си идет (дофига проектов на Си написано) или в еще какой-нить язык, где достаточно 10-ти страниц прочитать, чтобы весь язык освоить

kokoc88

Если писать развернутый функтор с параметрами для конструктора и не вытягивать его в одну строку, то все 10. И дело даже не в трех строчках, а в необходимости создания внешней сущности, что приводит к нарушению принципа инкапсуляции!
Я не понимаю, как ты собрался одно сравнение вытянуть в 10 строк? Использование boost::bind, которое есть в данной теме, эквивалентно следующей записи:
bool compare(const S& s1, const S& s2)
{
return s1.p < s2.p;
}

При чём тут инкапсуляция!11!

slonishka

или в еще какой-нить язык, где достаточно 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-тистраничном стандарте
возможен такой феерический пиздец.
кто нашел ошибку быстро, не пишите.
мне кажется, ее поиск - это очень важный экспириенс.

erotic

Бачан, жжошь. Нашел, только когда собрал, запустил, охуел, открыл в редакторе и посмотрел внимательно.

slonishka

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

erotic

Ну вообще, boost::bind - принят в 0x, поэтому любой уважающий себя С++'р должен его изучить. Если же человек, который занимается якобы "разработкой на С++", просто прочитал одного Кернигана и не хочет ничего больше изучать, то, блин, нех ему делать в программировании на С++, пусть в Си идет (дофига проектов на Си написано) или в еще какой-нить язык, где достаточно 10-ти страниц прочитать, чтобы весь язык освоить
Что касается моего мнения, то я считаю, что язык и его библиотеки лежат в двух разных плоскостях. Первое - возможности. Второе - реализованные возможности. Ориентироваться на второе неправильно.

Dasar

такое действительно должно компилится по стандарту? нафига им(стандартизаторам) такое понадобилось?
зы
давно считаю, что стандартизаторов C++ надо всех скопом посадить на кол. такой мощный язык поганят всякой херотенью, причем обычно с обоснованием, что мол так было принято писать в старину при царе горохе, поэтому в будущем так тоже должно быть можно писать.

slonishka

такое действительно должно компилится по стандарту?
нафига им(стандартизаторам) такое понадобилось?
ну оно по презумпции разрешенности, я так понимаю, компилится.
его нужно было специально запретить, но стандарты ж принимаются серьезными людьми.
там не додумались до такого, вот и живем.
самое стремное, что даже с -Wextra всякими оно выдает только один странный ворнинг "defined but not used".
я с тех пор к таким ворнингам отношусь серьезно.
вообще у ван дер линдена много и очень по делу про C-стандарт
сказано в его книге "Expert C Programming. Deep C Secrets".
я даже предположу, что он там перечислил *все* недостатки языка C,
что само по себе уже неплохо, т.к. есть шанс, что их количество конечно.
давно считаю, что стандартизаторов C++ надо всех скопом посадить на кол. такой мощный язык поганят всякой херотенью, причем обычно с обоснованием, что мол так было принято писать в старину при царе горохе, поэтому в будущем так тоже должно быть можно писать.
да, жаль C++, такой язык мог бы быть заебательский! :grin: :grin:

doublemother

Вообще, то, что это работает, проверить просто
Нет, я ни на секунду не сомневаюсь, что это работает :)
Мне интересно, как именно это устроено.

kokoc88

ну оно по презумпции разрешенности, я так понимаю, компилится.
Ошибку я нашёл после того, как не нашёл использование lambda. Зря ты про неё написал, это заставило внимательно прочитать код. А он что, компилируется?

slonishka

да, конечно компилится. goto чтоль ни разу не писал? :)
я долго думал, что лучше - спрятать ошибку посильнее, или наоборот - блиц-холивар.
в итоге плюнул и запостил как на душу легло.

kokoc88

goto чтоль ни разу не писал?
Ээээ.... нет. :o

Dasar

>ну оно по презумпции разрешенности, я так понимаю, компилится.
до меня дошло только после твоего ответа mike-у, что компилятор думает, что это название метки, и поэтому это хавает.

slonishka

а, клево! значит я все-таки не зря ответ тот писал.
спасает еще то, что на qwerty-клавиатуре "1" и "l" спутать довольно трудно.
если, конечно, не делать этого специально.
мой (удаленный) ответ майку:
короче, это же просто метка. компилятор не может ничего против сказать, т.к. с т.з. языка все по-честному
и вот лишь одна странность - метка не используется (т.е. нигде нет строчки "goto defau1t;"). =)

asvsergey

спасает еще то, что на qwerty-клавиатуре "1" и "l" спутать довольно трудно.

Ещё ide подсвечивает.

kokoc88

Ещё ide подсвечивает.
Ты что, true Си-шный код можно редактировать только под vi.

doublemother

Я копипастил в vim. Бага спалилась сразу же по отступам.

kokoc88

Нет, я ни на секунду не сомневаюсь, что это работает
Мне интересно, как именно это устроено.
Через шаблоны. Вот очень приблизительная механика. (Наверняка где-то не по стандарту, сделал на скорую руку в 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;
}

slonishka

Ещё ide подсвечивает.
метки обычно тем же цветом, что и case-конструкции подсвечены.
по крайней мере во всех IDE, что использовал я, было так.

slonishka

Я копипастил в vim. Бага спалилась сразу же по отступам.
поясни.

Marinavo_0507

я увидел быстро, ничего не компилировал и никуда не копировал
и у кого после этого шрифты говно? :grin:

slonishka

у меня тоже в форуме видно (code-области тахомой выводятся).
я хотел что-нибудь еденькое приписать про шрифты, ага.
вообще, ты мои шрифты хвалил когда-то, я всем хвастался потом.

Marinavo_0507

зато мои все ругали :)

slonishka

ыыы.
помню, как в далеком сентябре 2002-го зашел к тебе подключить интернет за 50 рублей.
чорный десктоп играл какой-то дет-, дес- или деф-метал, пока ты вбивал в него аццкие символы
каким-то неведомым пользователю Windows 98 Second Edition RUS шрифтом.
думаю, это был очень важный для формирования моего жизненного сценария экспириенс.

doublemother

Ахтунг. Спасибо.

kokoc88

Ахтунг. Спасибо.
Это сейчас что было?

doublemother

поясни.
Оп!

doublemother

Это сейчас что было?
Это я ужаснулся конструкции и поблагодарил тебя за разъяснение :)

slonishka

зачот. покажи вимрц.

Bibi

это стандартно. херачишь это без set paste, оно едет говном, потом ты все это выделяешь и жмешь равно, чтобы автоиндент сработал. тут оно и оно. а еще надо юзать хорошие шрифты, в терминус они очень хорошо отличаются

slonishka

жмешь равно, чтобы автоиндент сработал
ыыы. спасибо, я не пользовался им никогда.
вернее, я думал, что настройки автоиндента затрагивают те случаи,
когда вбиваешь новый код, а про кнопку <=> не знал. =)

slonishka

вообще, вместо ядра лучше б чужие вимрц транслировали.

erotic

это стандартно. херачишь это без set paste, оно едет говном, потом ты все это выделяешь и жмешь равно, чтобы автоиндент сработал. тут оно и оно. а еще надо юзать хорошие шрифты, в терминус они очень хорошо отличаются
Shift + Ins - едет говном.
Щелчок по колесу мыши - вставляется оригинально.

doublemother

я свой вимрц в альт.линуксе выкладывал :) тебе он, помнится, еще и понравился.

slonishka

я свой вимрц в альт.линуксе выкладывал тебе он, помнится, еще и понравился.
ага, ну они меняются (по крайней мере у меня так бывает). =)
а тут дело не в нем, как выяснилось.
макс, про >.< знаю, ага.

Werdna


более отмороженной аргументации не видел...

asvsergey

метки обычно тем же цветом, что и case-конструкции подсвечены.
по крайней мере во всех IDE, что использовал я, было так.

Эклипс не подсветил метку.

apl13


$ 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)

slonishka

да я понял, ден. у меня filetype indent отключен, я поэтому не знал про эту фичу. =)
ну в смысле, я там выше непонятно написал про вбивание нового кода, да.
я не то имел в виду, что там написано.
Оставить комментарий
Имя или ник:
Комментарий: