Как стать автором
Обновить

Комментарии 83

Я только начал вникать в С++0x, но уже сожалею, что убрали концепты. Спасибо за разъяснение. Надеюсь на продолжение.
Спасибо Вам за оценку. Следующей статьёй я думал написать о ссылках на rvalue (rvalue references) также из будущего стандарта.
Да, да, обязательно пишите — у вас это прекрасно получается. Я хоть и почитал уже довольно много про это, но лишним такое описание, как тут, не будет. Ждём!
Обязательно пишите, статья получилась очень хорошая и толковая (и потом — желания курить новый стандарт я в себе так и не нашел, а тут все понятно и доступно).
Пишите пожалуйста. Из нового стандарта rvalue refs — это самое мутное для меня, пожалуй. С удовольствием прочитаю.
Для простоты можете представить, что это «ссылка на ссылку» (по аналогии «указатель на указатель»).

Мне вот интересно, что GooRooнапишет, покольку я себе примерно представляю для чего это нужно, но он может что-то такое рассказать, что позволит эту фичу использовать ещё эффективней в будущем как говорится — «век живи — век учись» :)
НЛО прилетело и опубликовало эту надпись здесь
Слушай, чувак, респект и уважуха за столь подробное разжёвывание темы лямбда-выражений в С++. Очень порадовало, что ты не только рассказал всё более подробно, но и рассказал про подоснову всей этой кухни (это я про функторы). Теперь эти лямбда-выражения в C++ меня реально заинтересовали :) Обязательно теперь поэкспериментирую надосуге…
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
В последнее время наращивание вычислительной мощности процессоров замедлило ход, и развитие компьютерной техники пошло по пути распараллеливания вычислений. Поэтому в моду начнут входить чистые функциональные языки программирования, такие как Haskell к примеру, ибо в них это самое распараллеливание делается крайне легко. Но так как на текущий момент одним из нюансов является не слишком высокое быстродействие программ, написанных на Haskell, в сравнении с их C++-аналогами, скорее всего в будущем появится новая, гибридная методология, которая будет включать как элементы ООП и функционального программирования, так и, возможно, что-то совершенно новое. IMHO :)
Очень часто самое интересное получается как раз на стыке технологий.
Каким образом (анонимные) функторы противоречат ООП?
Если функтор принимает в качестве параметра другой функтор, а возвращает третий — это смотрится несколько странновато и непривычно, хоть, возможно, и не противоречит ООП.
Для C++ — пожалуй.
Последнее время, по-моему, для С++ уже нет ничего странного и необычного.
НЛО прилетело и опубликовало эту надпись здесь
Суть от этого не меняется.
НЛО прилетело и опубликовало эту надпись здесь
Если не злоупотреблять размерами лямбд, то ничего не усложняется. А так, в С++ полно мест, где можно очень неплохо на голову себе навесить проблем. Принципиально лямбды ситуацию не ухудшат.
Это не goto, это способ алгоритмической абстракции (здесь в статье хороших примеров нету, но подошло бы объяснение fold/map).

В ООП (которое message passing) такие «костыли» (лол) тоже есть, ибо сами сообщения — объекты первого класса.

Как раз таки *отсутствие* функций/сообщений первого класса приводит к костылям.
По сути, map — это transform, а fold (он же свёртка списка) — это accumulate, если я всё правильно понял. Это, конечно, очень грубо говоря…

Я только недавно начал учить Haskell, поэтому пока что не могу привести хорошие примеры :(
А то, что само ООП в С++ немного костыльное, вас не смущает?
да у меня то же что-то ругается на этом месте
Эм… Дело в том, что это фича из будущего стандарта C++, и сейчас она реализована только в Visual Studio 2010 Beta и отдельных бранчах gcc вроде как.
$ gcc-config -c
x86_64-pc-linux-gnu-4.4.1
получается в последнем gcc эта фича еще не реализована, очень жаль.

P.S. Хотя, с другой стороный, второй листинг скомпилировался без поблем.
Эта фича еще не вошла в trunk проекта gcc, потому что новый стандарт C++ по сути еще не вышел, но в отдельных сборках, я слышал, уже работает.

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

А так спасибо, очень интересно, в общем-то как и все новое (:
Учите Haskell ;) — там всё новое…
хах, буквально вчера за него принялся, действительно интересно :)
Статья действительно хорошая. А вот лямбды в c++ конечно выглядят громоздко. По той же причине, я использую замыкания в javascript но не использую анонимных функций т.к. это выглядит не так мило как в Lisp/Haskell/ML и проще объявить их рядышком.
суровая статья, спасибо
у меня вопрос: как все это будет работать без автоматической сборки мусора? я псал на С++ достаточно давно и уже не в теме, но не принесут ли лямбды в С++ лишней головной боли с утечками памяти? и вообще они каким-то образом влияют в этом вопросе или бояться нечего? мне было бы интересно узнать

за статью спасибо, жду продолжений и подобных статей, автор, пиши еще :-)
Ну если фактически компилятором это будет разворачиваться в функтор, то, мне кажется, утечек памяти это за собой не повлечет. В любом ведь случае эти лямбды будут создаваться совсем не динамически.
std::copy( a.begin(), a.end(), std::ostream_iterator( std::cout, " " ) );

а не надуманные трейслямбды
и опять ни слова про действие лямбды вне области видимости переменных.
Там есть и такое. Трейслямбда чисто для примера. Давайте тогда так:

int elementsInRow = 0;
auto traceLambda = [=] (int _val) mutable
{
        cout << _val << " ";
        if (++elementsInRow % 5 == 0)
        {
                elementsInRow = 0;
                cout << endl;
        }
};

А зачем elementsInRow обнулять если % 5 написано? Можно либо написать if (++elementsInRow == 5) либо убрать обнуление, без изменения смысла
Да, сорри, это у меня гибрид из двух разных версий :)

Без обнуления не пойдет… Мало ли, сколько у нас там элементов. Должно быть вот так:

int elementsInRow = 0;
auto traceLambda = [=] (int _val) mutable
{
        cout << _val << " ";
        if (++elementsInRow == 5)
        {
                elementsInRow = 0;
                cout << endl;
        }
};
Да, my fault. Хотя маловероятно что мы будем обрабатывать коллекцию с 2 миллиардами интов, это же 8 гигов памяти. Или в stl можно будет конструировать бесконечные списки как в haskell?
Насколько я знаю, бесконечных списков не предвидится. А 8 гигов памяти в наше время — не так и много…
Громоздко слишком. Вот в том же ATS (ats-lang.org) это делается проще и практически также эффективно.

Да-да, я понимаю, что это исследовательский язык и все такое, но С++никам следует обратить на него пристальное внимание.
НЛО прилетело и опубликовало эту надпись здесь
Скорее всего, это просто тренды, не следовать которым — отставать в практической применимости. С++ изначально представлялся конструктором, с помощью которого можно стоить не только дома, но и инструмент, с помощью которого эти дома делаются. Но когда количество самодельного инструмента превысило отметку в 9000, все-таки решили причесать этот зоопарк и ввести наиболее употребимое непосредственно в язык. Временами получается несколько неуклюже (как раз из-за начальной ориентации в перпендикулярном направлении): и синтаксис лямб — не верх изящества.
Только монад и pattern matching'а не хватает)
Не переживайте :) C++ — мультипарадигменный язык… Будут :))) гг
НЛО прилетело и опубликовало эту надпись здесь
В листинге 13 необходимо явно указывать возвращаемый тип первой лямбды -> void?
как сказал автор статьи — это тип возвразщаемый по умолчанию. Поэтому указывать его явно не обязательно
ну кроме случаев, когда тама есть один retun, который и определяет возвращаемый тип.
Да, -> void можно не указывать, а вот дальше -> function<int (int)> все-таки пришлось указать, потому что компилятор сам не смог вывести тип.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Есть неосвещённое белое пятно.
Что происходит со ссылками на переменные, вышедшие из области видимости?

function<void ()> foo()
{
int init = 0;
return [&init]() { ++init; };
}

Подозреваю, что со ссылкой ничего не произойдёт, после возврата из foo она будет указывать на адрес на стеке и использование результата функции foo() будет разрушать значение в этой ячейке стека.

Или я не прав?
> Есть неосвещённое белое пятно.
Мда, ну и фразу написал…
Grammar nazi негодуе.
Замените это на функторы и всё станет ясно.
Вы сохранили ссылку на переменную, которой после выхода из функции нет. Что в таком случае положено? Не важно, лямбда там или нет, обращение по этой ссылке — undefined behaviour.
Прекрасная статья, снимаю шляпу вместе с волосами перед умением автора доносить мыслю. Отплюсовался где только мог :)
спасибо за статью. тема сисек лямбда функций почти раскрыта
Спасибо. В следующий раз постараюсь донести больше сисек подробностей о фичах нового стандарта…
респект автору. статья очень полезная.
Спасибо, было приятно ознакомиться, пока еще не приходилось читать такого внятного рассказа о лямбдах в C++.
НЛО прилетело и опубликовало эту надпись здесь
Спасибо большое за ссылку! Почитал. Довольно интересно, но я так и не заставил себя всерьез заняться изучением Objective-C. На первый взгляд замыкания там действительно попроще, чем в C++ :)
НЛО прилетело и опубликовало эту надпись здесь
Если нужно компилировать только средствами от Apple, то это уже не чистые C/C++ ;)

P.S. Ей-богу, не осилил разобраться в XCode. Мне сказали, что XCode удобно использовать только для Obj-C, но не для C++. Посему с программингом под Mac у меня как-то вообще не сложилось.
НЛО прилетело и опубликовало эту надпись здесь
Я касательно C++ в последнее время вообще подсел на Qt, поэтому предпочитаю Visual C++ (которому IMHO нет равных) и Qt Creator.

А вообще сейчас пытаюсь переквалифицироваться в Haskell-программера :) Так что до Obj-C я точно не дойду.
НЛО прилетело и опубликовало эту надпись здесь
Не слышал, честно говоря. Мне продукты Apple нравятся, но я от них не настолько фанатею, чтобы все силы кидать на программинг под них.
а нетипизированные лямбда-функции существуют (в виде шаблонов)?
А зачем?
я же вас не спрашиваю, зачем ввели лямбду, когда спокойно обходилось обычными функторами. вот и вы, пожалуйста, тоже…

ладно, так уж и быть, отвечу на ваш вопрос. без лямбда-шаблонов новшество будет уступать функторам в гибкости.
Если ввели, значит «обходились неспокойно», однако для программистов С++ (не знакомых с функциональным программированием) лямбда-выражения скорее всего будут не более чем синтаксическим сахаром, который иногда весьма удобно использовать. Но Вам же никто не говорит заменять все функторы на лямбды.

А как Вы себе вообще представляете объявление шаблонной лямбды?
А так ли важно, как я их себе представляю? То, что паре программистов с хабра не удалось этот синтаксис себе вообразить, не должно наводить на мысль о невозможности или ненужности. Было бы желание, а синтаксис придумать можно. Да хоть включив объявление параметров шаблона в начало списка параметров функции:

[]...(typename T1, typename T2, int i, T1* pt1, const vector& v) {...}

Но на самом деле мне не нравятся две вещи. Во-первых, синтаксис — недостаточно элегантно для меня, чтобы отдавать ему предпочтение. А во-вторых, вложенные лямбды будут отрицательно сказываться на удобочитаемости кода (впрочем, этот момент мне даже в лиспе не нравился, когда мы его изучали в университете).
Опечатка в последнем параметре шаблонной лямбды, хабраредактор съел параметры вектора из-за угловых скобок. Вектор должен быть инстанциирован типом T2.
После прочтения статьи волосы встали дыбом. C++ такой C++. В C# просто пишешь лямбду и не задумываешься, какой нафиг у переменной захват, mutable/не mutable, что такое анонимный функтор с перегруженным оператором и так далее. Неужели ЭТИМ будет кто-то всерьез пользоваться? Да тут можно таких дров наломать, что потом неделю отлаживать придется.
Программисты на С++ привыкли думать во время работы. Если для Вас это непривычно, то продолжайте C#, незачем терзать себя таким страшным языком, как С++.
*писать на C#
Зачем вы так) Я очень люблю C++ (и написал на нем много кода), просто утверждаю, что в языке стало больше на одно место, где можно эпически облажаться начинающим программистам.

Думать это правильно, но ведь зачем-то придумали абстракции, чтобы упростить жизнь нашему брату. Можно писать на ассемблере например, там очень сильно думать надо. Введению auto я очень рад, он избавляет от рутинной работы. Лямбды по идее тоже избавляют от рутинной работы, но… Когда есть с чем сравнивать, становится неловко. Если бы они появились в середине девяностых, они произвели настоящий фурор. Но не в наше время.
И да, появился новый вопрос на собеседовании, соберется ли код
int main{[](){}()}

:)
Тьфу, то есть
int main(){[](){}();}

Статься содержит ошибку. Так не разрешается

[&, x, &y] // захват всех переменных по ссылке, кроме x…

Если указан захват по умолчанию &, то все явные захваты должны быть по значению. То есть &y в данном списке не допускается.

И наоборот, если указан захват по умолчанию =, то все явные захваты должны быть по ссылке.

Изначально я предположил, что в 2009 году черновая версия спецификации не содержала такого ограничения, но несложно проверить, что это ограничение присутствовало с самого начала.

Возможно :)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации