Лямбда выражения теперь и в С++

    image
    Многие языки программирования позволяют создавать налету локальные не именованные функции внутри выражений. К этим языкам относятся C#3.0, Python, ECMAScript и практически все функциональные языки программирования (например, Haskell и Scheme). Такие функции обычно относят к лямбда функциям, которые имеют широкое применение.

    C++0x– неофициальное название нового стандарта языка C++, который, как планируется, должен заменить существующий стандарт(ISO/IEC 14882), который был опубликован в 1998 и обновлен в 2003. Предшественники также известны, как C++98 и C++03. Новый стандарт добавит несколько дополнений в язык и расширит стандартную библиотеку C++. Одно из расширений языка – возможность использования лямбда выражений. Очень приятно, что уже сегодня данная возможность реализована для VisualStudio 2010 и GCC.
    imageimage

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

    Напомню, функциональные объекты – это обыкновенные объекты с перегруженным“()”оператором. Таким образом, с точки зрения синтаксиса, они являются обыкновенными функциями.

    Для начала давайте рассмотрим пример с использованием указателя на функцию. Представим, что нам нужно заполнить массив числами от 0 до 19, один из вариантов заполнения массива, используя текущий стандарт, приведен ниже.
    image

    Минус данного решения в том, что мы не можем отслеживать состояние нашей переменной “value” вне функции.
    Теперь реализуем туже самую задачу с помощью функционального объекта. Вариант реализации приведен ниже.
    image
    Это техника прекрасно работает и позволяет отслеживать состояние переменной “n”, но она требует объявления класса.

    А теперь давайте посмотрим, как просто можно выполнить ту же самую операцию, используя лямбда выражение.
    image

    Синтаксис лямбда выражения:
    image
    1) Маска переменных
    2) Список параметров
    3) Изменение параметра, переданного по значению
    4) Спецификация исключения
    5) Возвращаемый тип
    6) Тело лямбда выражения

    Маска переменных
    Лямбда выражение может получать доступ практически к любым переменным и использовать их внутри тела. Снимок определяет способ получения параметров телом лямбда выражения. Доступ к переменным, перед которыми стоит амперсанд (&), осуществляется по ссылке, а перед которыми нет амперсанда, соответственно по значению. Пустая маска ([]) означает, что тело выражения не имеет доступа к переменным.

    Стандартная маска определяет, получаем ли мы доступ к переменной по ссылке или же по значению. Устанавливая “&”, все значения будут получены по ссылке. Используя же“=”, переменные будут получены по значению. Например, если тело лямбда выражения получает доступ к внешней переменной “total” по ссылке и переменной “factor” по значению, маска должна быть записана следующим образом:
    image
    Также, вы можете использовать лямбда выражение внутри метода класса. Передавая указатель “this”, вы можете получить доступ к методам и членам данного класса.

    Список параметров
    Список параметров лямбда выражения содержит список параметров для функции, у которых существуют следующим ограничения:
    1) Список параметров не может содержать значения по умолчанию
    2) Не может содержать неименованные параметры
    3) Ограниченное число параметров
    image
    Также лямбда выражение может принимать в качестве параметра другое лямбда выражение. С другой стороны, список параметров является опциональным элементов, и можно писать выражение, не включая его.
    image
    Изменение параметра переданного по значению
    Спецификация позволяет разрешить телу лямбда выражения и заменить переменные, полученные по значению.
    image
    Спецификация исключений
    Лямбда выражения может включать в себя спецификацию исключения, которая позволяет телу не создавать исключения.
    image
    Возвращаемый тип
    Спецификация определяет возвращаемый тип лямбда выражения. Вы можете не использовать данную конструкцию, если тело выражения имеет только одну инструкцию “return” или не возвращает значения вообще. Если тело содержит только одну “return” инструкцию, компилятор установит возвращаемый тип лямбда выражения идентичный типу “return” инструкции.
    image
    Тело лямбда выражения
    На тело выражения накладываются идентичные ограничения, как на блок кода или метод.

    Данная фича уже доступна в VisualStudio 2010 и GCC, думаю, она вам поможет сделать ваш код еще лучше.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 142
    • 0
      Впервые вижу чтобы код был больше заголовков
      • 0
        У меня в хабраредакторе не получается задать размеры =(
        • 0
          Размеры картинок?
        • 0
          это картинки, причём тут хабраредактор:)
        • +6
          Тем не менее читать очень даже удобно, сам никогда не думал что код большим кеглем будет выглядеть нормально.
          • +1
            Имхо, для небольших кусочков кода это намного лучше нежели как обычно. А если простыня кода, то тогда конечно лучше по стардарту, так сказать :)
          • +1
            Вот и отлично. Подслеповатые вроде меня в кои-то веки могут без надрыва читать листинги.
            У меня в MSVC такой же шрифт.
            • 0
              Так как лучше? Я их немного отресайзил…
        • +3
          Как-то [спорно], что Java «позволяет создавать налету локальные не именованные функции внутри выражений».
          Это как? Только не говорите про анонимные классы. Класс — не функция.
        • +38
          С каждым новым витком развития С++ его синтаксис становится всё страшнее и страшнее.
          • +3
            Я, конечно, пускаю скупую слезу когда вижу более читабельный C#-код, но к C++ и всем этим multiple inderections довольно легко привыкнуть, если этим заниматься, а не смотреть из-за угла.
            Из-за угла — да, страшно.

            Ну и представьте каково разбирать подобное адептам визуального бейсика.
            • 0
              Думаю вы правы, но в случае .NET: «зачем платить больше, если не видно разницы?»
              • +1
                А если отвлечься от x86 и посмотреть на другие платформы? C++ есть почти под всё (так как есть C), чего не скажешь про .Net.
                • +1
                  C++ есть почти под всё, но почти под все он немного различается. Иначе не было бы https://developer.mozilla.org/En/C___Portability_Guide.
            • –2
              Согласен. Ну почему нельзя было сделать синтаксис, похожий хотя бы на Python?
              • 0
                Но это же очевидно — обратная совместимость. Если радикально изменить синтаксис C++ — это будет совсем другой язык. Python, D, или что-то ещё. К тому же, как было замечено выше, к синтаксису плюсов, при постоянной работе, довольно быстро привыкаешь. :)
              • 0
                Вот, вот. Судя по комментам ниже не во всех функциональных языках такой синтаксис на данную фичу… Интересно было знать зачем такой страшный синтаксис описания лямбда-выражений ввели. Может кто-то ссылочку кинет, а то кателок уже не варит после рабочего дня, а быстро нагуглить не удалось.
                • +4
                  вероятно чтобы имеющийся код остался рабочим. использовали конструкции невозможные в предидущем стандарте
                  • 0
                    Насколько я предствляю, в с++ невозможны были и конструкции лямбда выражений из c#, так что могли бы сделать более вменяемый синтаксис.
                    А вообще эта погоня за обратной совместимостью и бесконечные костыли делают с++ просто нечитаемым.
                • 0
                  Все равно, до перла ему далеко (:

                  ЗЫ: Перл я тоже люблю :)
                  • +6
                    Теперь фактически вот это валидный код на C++:

                    int main(){[](){}();}

                    • 0
                      Черт возьми, ниже такое уже написали :)
                    • 0
                      Этак скоро C++ превратится в Perl или что-то подобное…
                      :)))
                    • 0
                      альтернативный вариант: habrahabr.ru/blogs/macosxdev/66632/

                      ps. Запутанность С++ только могила исправит. Простите :)
                    • 0
                      так держать :p (http://artlung.com/smorgasborg/Invention_of_Cplusplus.shtml)
                    • НЛО прилетело и опубликовало эту надпись здесь
                      • НЛО прилетело и опубликовало эту надпись здесь
                        • +2
                          Это вы троллите так нетолсто, а я под вечер уже не могу различить, или всё на полном серьёзе?
                          • НЛО прилетело и опубликовало эту надпись здесь
                            • 0
                              Ну, GCC всего лишь один из компиляторов, а лямбда-функции добавили в стандарт С++, а не только в одну конкретную реализацию компилятора С++. А из вашего поста было не очевидно, что претензия именно к GCC.
                              • НЛО прилетело и опубликовало эту надпись здесь
                                • +2
                                  C++ не императивный язык. И не объектно-ориентированный. Он мультипарадигменный. Кто как хочет, так и программирует. Никто ж не заставляет использовать все без исключения возможности языка. С другой стороны, если лямбда-функции в каких-то местах значительно сократят код и не будут являться ботлнеком, то даже с плохим (допустим) GCC — почему нет?
                                  • НЛО прилетело и опубликовало эту надпись здесь
                                  • НЛО прилетело и опубликовало эту надпись здесь
                                    • НЛО прилетело и опубликовало эту надпись здесь
                                      • НЛО прилетело и опубликовало эту надпись здесь
                                        • +2
                                          Будущее наступило, ничего не убрали.
                                          www.python.org/dev/peps/pep-3099/
                                  • 0
                                    >чтобы было
                                    Я подозреваю, что сделали потому, что это не так уж и тяжело сделать, да и не грех пополнить список оптимизаций.
                                    • НЛО прилетело и опубликовало эту надпись здесь
                                • 0
                                  >Когда-то Си был таким удобным, приятным языком
                                  Ну кагбе каким он был таким он и остался
                                  • НЛО прилетело и опубликовало эту надпись здесь
                                    • НЛО прилетело и опубликовало эту надпись здесь
                                      • +3
                                        Хватит уже называть С++ Сями. Это разные языки.
                                      • 0
                                        что за язык это C/C++?
                                        • НЛО прилетело и опубликовало эту надпись здесь
                                          • –1
                                            "++" в названии — это не столько объектно-ориентированность, сколько препроцессор, если я ничего не путаю.
                                            • НЛО прилетело и опубликовало эту надпись здесь
                                              • +1
                                                ++ есть и в Си.
                                                • 0
                                                  Человеку, поставившему минус: Просьба ознакомиться с пунктами 6.5.2 и 6.5.3 стандарта языка Си (ISO/IEC 9899:1990). Ну или проверить компилятором.
                                                  • НЛО прилетело и опубликовало эту надпись здесь
                                                    • 0
                                                      Впервые слышу о таком. В книге Кернигана и Ричи уже есть про ++ и --.
                                                      • 0
                                                        Все гораздо проще, название «С++»:
                                                        «С» — как дань предшественнику и основе языка;
                                                        "++" — как указание на усовершенствование.
                                                        А оператор ++ был и в Си.
                                          • 0
                                            Ты не понел, Си таким как был таким и остался, это Си++ мутирует. BTW си это тоже static scope язык, и сделать лексические замыкания не так сложно.
                                      • +1
                                        а tail recursion поддерживается?
                                        • +2
                                          Да, конешно
                                          int fact = [](int x) -> int
                                          {
                                          int accumulator = 1;
                                          beginning:
                                          if (x == 0) return accumulator;
                                          else
                                          {
                                          accumulator *= x;
                                          x -= 1;
                                          goto beginning;
                                          }
                                          }(n);
                                          • 0
                                            вам не трудно пояснить?
                                            … }(n) меня слегка ушибло
                                            • 0
                                              int fact = [](int x) -> int{...}(n)
                                              То есть просто вызов этой лямбды
                                              • 0
                                                Передача n в лямбду в качестве аргумента, если я правильно понял.
                                              • 0
                                                :D не, так не интересно…
                                            • +6
                                              Лямбды в С++… все, нам конец :(
                                              • +1
                                                Ну, во-первых, не будем торопиться: из черновика C++0x выбросили концепты, а это была более долгожданная и всячески восхваляемая фича.

                                                Во-вторых, тем, кто использовал Boost.Lambda, станет легче, и это хорошо. А для прочих ничего не изменится :)
                                                • +1
                                                  Согласен. Жалко, что их убрали =(
                                                  • 0
                                                    По по-поводу того что для других ничего не изменится должен не согласится. Раз появляются дополнения к синтаксису значит их надо знать, как минимум для собеседований.
                                                    А язык и так громадный с множеством тонкостей. Лучше уж библиотека чем такие рывки.
                                                  • –2
                                                    верните «С с классами»!
                                                    • +2
                                                      Не используйте лямбды, не используйте исключения, не используйте шаблоны. Пишите себе на «С с классами», кто вам мешает? Его никто никуда не забирал.
                                                  • 0
                                                    как выглядит передача лямбда функции — обьявление «принимающей» стороны?
                                                    • 0
                                                      Про второй не уверен, будет оно или нет.
                                                      std::tr1::function
                                                      std::tr1::reference_closure // ?
                                                      T // template <class T>
                                                      • 0
                                                        в качестве примера
                                                        std::tr1::function<void (int)> print = [](int n) { std::cout << n; };
                                                      • +16
                                                        теперь в C++0x легальным стало выражением:
                                                        [](){}();
                                                        • 0
                                                          прошу прощения за опечатку «выражение».
                                                        • +1
                                                          Скрестили ежа со змеей, блин…
                                                          • 0
                                                            Ну вообще те, кто говорят о том, что «не хотите — не используйте» в каком-то смысле правы. Действительно не понятно, на кой именно эта фича нужна (мне она нахрен не сдалась). Но вот мне необходимы шаблоны с переменным числом параметров, но я больше чем уверен, что найдутся недовольные, которые будут орать о том, что введение данной фичи только испаганит язык… Так что тут бабушка на двое сказала и что действительно хорошо, а что не очень — нужно много и основательно думать.
                                                            • 0
                                                              Хрен знает насчет С++ — давно ничего сложного на нем не писал, но в других языках постоянно юзаю
                                                              насчет орущий +пятьсот, каждый хитрый выверт таких порождает, потому как въезжать в это нужно. Часто материал подается в руководствах по новым фичам через жопу, потому как авторы манула еще сами не поняли на кой оно им. Последние курсы майкрософта вобще жесть сплошная.
                                                              • 0
                                                                По моему вводить что-то новое всё таки нужно, но при этих нововведениях главное как можно меньше похерить того, что уже было. И если нововведение не затрагивает то, что существовало до него или сказывается очень несильно, особенно для таких столпов как C++, то я скорее за нововведения. Ну вот как пример в лямбда-выражениями: действительно такой несколько извратный синтаксис ввели, чтобы наверное не похерить ту идеологию в написания кода, которая сложилась до этого и существовала без лямбда-выражений. Главное ещё в этом стремлении «не похерить» совсем уж в крайность не впадать и если уж что-то вводить, то не просто некий набор того, чего до этого не было, а подложить под это дело хоть какую-то логику.
                                                          • +3
                                                            молодцы, но синтаксис ужасен
                                                            • НЛО прилетело и опубликовало эту надпись здесь
                                                              • +1
                                                                ну да, там так и написано — 0х :)
                                                              • 0
                                                                Прочитал внимательнее, запутался. Во-первых, какой тип получается у этих лямбда-выражений? Они вообще кто? Объекты? Если я хочу его в переменную сохранить, то что писать надо?
                                                                Откуда берутся переменные не объявленные в скобках? Из текущего контекста, из контекста применения выражения?

                                                                > Также лямбда выражение может принимать в качестве параметра другое лямбда выражение. С другой стороны, список параметров является опциональным элементов, и можно писать выражение, не включая его.
                                                                Неплохо бы уточнить, что результат скорее всего будет отличаться. Выражения [=]{return x;} и [=](int x){return x;} вообще-то разные вещи (надеюсь :))
                                                                • 0
                                                                  1)[=]{return x;} и [=](int x){return x;}
                                                                  Да, будет отличаться! В первом случае переменная «x» будет взята из контекста, второй вариант вернет входной параметр
                                                                  • 0
                                                                    Я к тому, что это надо отразить в статье, т.к. из того примера, что там, разница не видна
                                                                  • +3
                                                                    Я собирался написать статью про лямбды в C++, но меня опередили. Пожалуй, я все-таки напишу, ибо эта недостаточно подробная.
                                                                    • 0
                                                                      Да, тема здесь раскрыта не достаточно. Нужно подробнее.
                                                                  • +2
                                                                    Мне кажется, что «хорошим кодом» считается тот, который понятен многим.
                                                                    А код «о, смотри, какую я штуку написал! угадай, что оно делает?» — плохой код, потому что он отнимает уйму человекочасов на поддержке.
                                                                    Не сильно понимаю, как конструкция из множества скобок и спецсимволов (которую большинство постарается ещё и в одну строку записать) поможет «сделать код лучше»? Примером «как не стоит писать»?

                                                                    PS: функция inc() случаем не ноль всегда возвращать будет? Кажется, там логическая ошибочка с местом инициализации переменной value ;)
                                                                    • +4
                                                                      вот видите, даже без лямбд код вы не поняли ;)
                                                                      почитайте на досуге, что означает модификатор static
                                                                      • –4
                                                                        Я то как раз понял, А Вы? А запустить код пробовали?

                                                                        // test.cpp, code begin
                                                                        #include using namespace std;

                                                                        int inc() {
                                                                        static int z = 0;
                                                                        return z++;
                                                                        }

                                                                        int main(void) {
                                                                        for (int i = 0; i < 5; i++) {
                                                                        cout << int() << endl;
                                                                        }
                                                                        return 0;
                                                                        }
                                                                        // code end

                                                                        ~$ g++ test.cpp && ./a.out
                                                                        0
                                                                        0
                                                                        0
                                                                        0
                                                                        0
                                                                        ~$

                                                                        Думайте, прежде чем минусовать
                                                                        • 0
                                                                          Прошу прощения, ступил. «int()» вместо «inc()» использовал, а статики из другой оперы вспомнил
                                                                      • +1
                                                                        C++ уже давно вышел из той стадии (а может никогда в ней и не был), когда код был понятен многим. С++ — сложный язык с высоким порогом вхождения, это никто не скрывает и не стремится исправлять.
                                                                        • 0
                                                                          Ну «начала» у этого языка не сложнее чем у других языков программироваия. Но вот наличие разных удобных фичек, о которых узнаёшь постоянно в процессе использования языка, меня лично радует несказанно :) Тот же static внутри функции, про который зашёл разговор — классная весчть, которая, к сожалению, конечно непонятна человеку, который только недавно начал программить на этом языке (сам наступал на эти грабли со static, когда не мог понять как это работает, правда даааавно это было). Язычок конечно посложнее многих _современных_ будет и глупости всвязи с его достаточно большой универсальностью можно понаделать массу. Но зато всегда есть куда развиваться — мне как разработчику и языку как языку, чтобы постараться сгладить некоторые острые углы.

                                                                          В какой-то книге встречал фразу чувака, который давно программит на нём и уже может считаться гуру (не дословно, но смысл передам): «Я программлю на C++ уже N лет, но даже с моим опытом я делаю по крайней мере одну глупость каждый день»
                                                                          • 0
                                                                            Хм. И у Вас static внутри функций особенный какой-то? Начинаю сомневаться уже.
                                                                            А что за версия C++ с «волшебными статиками»?
                                                                            • 0
                                                                              Прошу прощения, ступил. «int()» вместо «inc()» использовал, а статики из другой оперы вспомнил
                                                                              • +1
                                                                                Ну static в C++ действительно имеет довольно разные назначения:

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

                                                                                2. для переменных в классах это означает, что эта переменная одна для всех объектов и наследников и меняя значение этой переменной для одного объекта оно меняется для всех объектов этого (или наследованного) типа. Применение: подсчёт указателей на память, например.

                                                                                3. переменных и функций, объявленных глобально с cpp-файле это означает, что область видимости этой переменной ограничена только этим файлом.

                                                                                4. для методов, которые static это превращает их практически в аналог глобальных функций для вызова которых не нужно создавать объект этого класса. Отличие от глобальных функций только вроде только в том, что на статические функции работает правило области видимости, т.е. приватную или протектную ты объявить где угодно не сможешь.

                                                                                Ну вот то немногое, что просто «на коленке» вспомнил особо не задумываясь. Потому " static is a miracle !" :)
                                                                                • 0
                                                                                  Я немножко не в курсе, поясните плиз:
                                                                                  * Инициализировать static-поле при декларации (случай 2 в Вашем списке) разве нельзя? Если можно — то он идентичен случаю 1

                                                                                  * В случае 3 — слово static делает объявленя приватными? Замысловато, однако. А почему в стандарте для этого не предлагается слово типа private?

                                                                                  * 4-ый случай — это как в Delphi объявление методов класса с помощью слова class? Интересно, почему тут оно объявляется словом static? Или они имеют ввиду, что метод — это типа ссылка на функцию, делают эту ссылку независимой от экземпляра, «статичной»?

                                                                                  * В фразе «приватную или протектную ты объявить где угодно не сможешь» — тут Вы имели ввиду «вызвать» а не «объявить», или я что-то не понял?
                                                                                  • +1
                                                                                    static-член класса может быть проинициализирован при декларации только если он const и является интегральным типом либо перечислением. Хотя многие компиляторы позволяют это делать и в других случаях, это отклонение от стандарта.

                                                                                    В случае 3 static функции и переменные не являются членами какого-то класса, static ограничивает область доступности этих переменных и функций текущей единицей трансляции.

                                                                                    Потому что эти методы могут вызываться без создания экземпляра класса (к статическим членам-данным тоже можно обращаться без создания экземпляра), кроме того, они могут доступаться к любым статическим (в том числе и приватным) членам-данным класса.
                                                                                    • 0
                                                                                      Кое что узнал новое из твоего коммента. А именно что можно спокойно инициализировать статическую переменную при объявлении внутри класса, если она констрантна. Быстренько накатал программульку, скомпилил, работает! Никогда в голову не приходило, хотя программлю на C++ уже не первый день. Как говорится: «Век живи — век учись». Спасибо.
                                                                        • 0
                                                                          Хе, меня очень радует что это вводят… иногда не хватает лямбд, а с бустом как то не сложилось (без него обходился, так как в основном Qt)…
                                                                          • 0
                                                                            Подробнее описание и обсуждение новых фич (там правда начиналось обсуждение, когда еще не выкинули концепты) можно посмотреть на этом форуме: forum.sources.ru/index.php?showtopic=190375
                                                                            • +1
                                                                              >Лямбда выражение может получать доступ практически к любым переменным и использовать их внутри тела.

                                                                              Непонятная формулировка. Что значит к практически любым? Может к переменным из текущей области видимости?
                                                                              • 0
                                                                                Имеются виду переменные текущего блока кода.
                                                                              • +2
                                                                                Лямбда живет только в теле функции или её можно возвращать как результат и принимать как параметр?
                                                                                • 0
                                                                                  по поводу поддержки лямбды в GCC — это наглая ложь :(

                                                                                  gcc.gnu.org/gcc-4.5/cxx0x_status.html

                                                                                  вот смотрим статус еще не вышедшей но разрабатываемой 4.5 :-( :-(
                                                                                  • 0
                                                                                    хотя якобы есть отдельная ветка gcc — parasol.tamu.edu/groups/pttlgroup/lambda/ но непонятен статус этой ветки
                                                                                    • 0
                                                                                      Я лично не проверял, но на сайте у них написано " экспериментально "
                                                                                      • 0
                                                                                        понятно, значит может быть в 4.5 включат, а может и не включат. Попробую дома на VS2010
                                                                                  • 0
                                                                                    Мне вот что интересно, какие еще применения могут быть у лямбды кроме как обертка к глобальной переменной? Уж сильно выбивает предполагаемый синтаксис.
                                                                                    • 0
                                                                                      итераторы
                                                                                      • 0
                                                                                        видимо вы не знакомы или очень мало пользуетесь boost и stl
                                                                                        • 0
                                                                                          boost практически не пользуюсь. А в случае stl, уж не знаю интерфейсы-то устоялись, в основном. Или вы о чем-то другом?
                                                                                          • 0
                                                                                            в статье отличный пример с использованием стандартного алгоритма, а уж всякие

                                                                                            std::for_each
                                                                                            std::accumulate
                                                                                            std::copy
                                                                                            std::transform

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

                                                                                            for( i = 0; i<container.size(); ++i){
                                                                                            //somecode
                                                                                            };
                                                                                            • 0
                                                                                              ладно с for_each. То что можно в sort или stable_partition на месте написать что надо делать вот это будет замечательно.
                                                                                              • 0
                                                                                                а что, вы stl контейнеры только сортируете и ничего больше с ними не делаете? :)
                                                                                                • 0
                                                                                                  Понятно что не только сортирую. Просто внятной заменой for_each и компании является обычный for. Что в конкретном случае удобнее зависит от многих факторов, но замена одного на другое обычно не принесет такой кучи проблем как написание своей реализации qsort.
                                                                                                  • 0
                                                                                                    оригинально конечно, вы что предпочитаете писать каждый раз

                                                                                                    for( iter=container.begin();iter!=container.end(); ++iter){
                                                                                                    //some code on *iter
                                                                                                    };

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

                                                                                                    end_iter=container.end()

                                                                                                    потом вспоминать, что *iter тоже функция и лучше бы ее тоже отдельно взять:
                                                                                                    elem &e= *iter;

                                                                                                    не проще ли сразу:

                                                                                                    std::for_each( container.begin(), container.end(), [&](){//some code here} );

                                                                                                    ? :)
                                                                                                    • 0
                                                                                                      Хм компилятор который не заинлайнит container.end() в данном случае это что-то страшное =).
                                                                                                      И да я рад возможности писать for_each с лямбдами, но опять же есть достаточно простые пути без него обойтись (даже на странном компиляторе =).
                                                                                                      • 0
                                                                                                        а какая разница заинлайнин он или нет? это какаято работа, .end() у нас в общем случае это не одна строка кода, смотрим к примеру для вектора:

                                                                                                        end()
                                                                                                        { return iterator(this->_M_impl._M_finish); }

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

                                                                                                        а если посмотреть в std::string::end() или еще какой-нибудь сложный контейнер?

                                                                                                        • 0
                                                                                                          В общем случае заинлайнить container.end() невозможно, так что надо на практических примерах смотреть или писать, как упомянули выше.
                                                                                                • 0
                                                                                                  хммм… в принципе, картина прояснилась. Спасибо.
                                                                                          • –1
                                                                                            Мдаа, на редкость долбанутый синтаксис, круче только Перл — он абсолютно невменяем.
                                                                                            • +1
                                                                                              синтаксис в угоду компактности, для которой собственно лямбда и предназначена
                                                                                            • +2
                                                                                              В коментариях много пишут про корявый синтаксис. Как по мне это достаточно удачная попытка вставить замыкания в язык без сборщика мусора. Компилятор мало знает про планы программиста о жизни переменных и о том считает ли он их «тяжелыми» или нет. Поэтому надо же как то указать что передается по значению а что по ссылке.

                                                                                              Насчет полезности: кроме очевидных примеров с stl функциями которые требуют функтор можно найти еще кучу применений. Например кода есть куски кода которые очень похожи, но если их вынести в отдельную функцию то надо передавать 28 переменных. В таком случае можно объявить лямбда функцию и вызывать ее прямо на месте.
                                                                                              Те же qt сигнали реализованные на tr1::function + лямбда функции были бы гораздо удобнее.

                                                                                              Вобщем по-моему замечательное дополнение к языку
                                                                                              • 0
                                                                                                как это мало знает? :)

                                                                                                лямбда функция живет в блоке кода :) ей доступны переменные «на стеке» из этого блока, по выходу из блока все прекрасно «со стека» уберется :)

                                                                                                лямбда функция переданная как параметр в другой блок — не имеет доступа к переменным текущего блока :) поэтому никаких проблем без сборщика мусора нет.

                                                                                                Вообще в старом с++ всё тоже самое можно было бы сделать «ручками» написав чтото типа

                                                                                                class MyLambda{
                                                                                                sometype &someval;
                                                                                                sometype &someval;

                                                                                                public:
                                                                                                MyLambda( &some, &some… );
                                                                                                void operator()( params )
                                                                                                };

                                                                                                но каждый раз это делать несколько задалбывает
                                                                                                • 0
                                                                                                  void f() {
                                                                                                  int* ptr = new int(0);
                                                                                                  return [=](){return (*ptr)++;};
                                                                                                  }

                                                                                                  по мне так все нормально с доступом к перемнной на стеке в текущем блоке и передавать ее надо по значению. В другом месте надо по ссылке передать. Так что не все понятно.
                                                                                                  • 0
                                                                                                    вы всегда так бесстрашно с сырыми указателями в с++ работаете? :)

                                                                                                    я еще мощнее вам могу пример рассказать из с++

                                                                                                    int *f(){
                                                                                                    int val = 0;
                                                                                                    return &val;
                                                                                                    };

                                                                                                    тут уже выше неоднократно высказывалось, что если инструмент позволяет гвоздь и забить, и закрутить и закатать внутрь стены, а мастер знает только то что инструмент для закатывания, то мастер сам себе дурак :)
                                                                                                    • 0
                                                                                                      Что-то у нас не выходит осмысленного обсуждения. Я привожу пример который хочется записать одной строчкой а вы мне объясняете что я ничего не понимаю и с указателями так работать нельзя. То ли у меня не получается выражать свои мысли то ли у вас их понимать а может и то и другое. Я думаю стоит свернуть дискуссию и признать что вы во всем правы =).
                                                                                                      • 0
                                                                                                        наверное ваш пример должен выглядеть так:

                                                                                                        int f(){
                                                                                                        int *ptr = new int(0);
                                                                                                        return [=](){ return (*ptr)++ };
                                                                                                        };

                                                                                                        да вы тут потеряете память, но причем тут лямбда функции?

                                                                                                        точно также можно написать без лямбды:

                                                                                                        int f(){
                                                                                                        int *ptr = new int(0);
                                                                                                        return (*ptr)++;
                                                                                                        };
                                                                                                        • 0
                                                                                                          Прошу прощения на самом деле я хотел написать

                                                                                                          tr1::function<int(void)> f() {....}

                                                                                                          Если вас волнует потеря памяти (я понимаю при работе с c++ это уже инстинкт =) то можно написать что-то вроде.
                                                                                                          typedef tr1::function<int(void)> F;
                                                                                                          pair<F, F> f() {
                                                                                                          shared_ptrptr(new int(0));
                                                                                                          return make_pair([=ptr](){ return (*ptr)++;}, [=ptr](){ return (*ptr)--;});
                                                                                                          }
                                                                                                          Понятно что такое решение ни полраза не потокобезопасно. Но с другой стороны мы получили пару функций связанных одной переменной без необходимости хранить эту переменную где-то еще.

                                                                                                          У нас наблюдается терменологическая путаница. Есть лямбда функции. Они в данном контексте не более чем функции без имени. Так сказать «syntactic sugar». Но часто вместе с лямбда функциями используются замыкания. Замыкания как я представляю нужны для того чтобы сохранить часть переменных для последующего использования внутри лямбда функции.

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

                                                                                                          например
                                                                                                          void f(vector* v) {
                                                                                                          hash_setbig_hash_set;
                                                                                                          // fill big_hash_set
                                                                                                          stable_partition(v->begin(), v->end(), [&big_hash_set](int i) { return big_hash_set.count(i); }

                                                                                                          }

                                                                                                          Если бы мне пришлось разрабатывать замыкания в c++, то я бы, скорее всего, остановился на том, чтобы все хранить по значению. Те кого это не устраивает могли бы передавать все через указатели (умные и не очень). В таком случае мой пример выглядел бы как

                                                                                                          void f(vector* v) {
                                                                                                          hash_setbig_hash_set;
                                                                                                          // fill big_hash_set
                                                                                                          hash_set* big_hash_set_ptr = &big_hash_set;
                                                                                                          stable_partition(v->begin(), v->end(), (int i) { return big_hash_set_ptr->count(i); }

                                                                                                          }

                                                                                                          С другой стороны та реализация которую предлагают в стандарт мне тоже нравится.
                                                                                                          • 0
                                                                                                            умный указатель это всё равно лишний оверхед, так что правильно что в стандарте можно указать рефересить или копировать.

                                                                                                            замыканий как таковых (как я понимаю из текущего стандарта) лямбда-функции не реализуют, так как все переменные объявленные внутри лямбда функции будут при каждом вызове переобъявляться и по выходу из лямбды удаляться из стека.
                                                                                                            • 0
                                                                                                              Насколько я понимаю сущность замыканий, они хранят переменные которые видны в блоке где объявляется лямбда функция. Переменные объявленные в лямбда функции будут переинициализированны. А переменные которые объявлены в том же блоке что и лямбда функция будут храниться.
                                                                                                              Может я не прав, но тогда не понятна зачем эта бодяга с хранением по значению или ссылке.
                                                                                                              • 0
                                                                                                                если по значению, то все что мы делаем с этими переменными внутри лямбды — никак не отражаются на лямбде

                                                                                                                если по ссылке, то отражается.

                                                                                                                Насчет замыканий. Было бы странно ожидать работоспособности такого кода:

                                                                                                                boost::function<void()> func;

                                                                                                                void f(){
                                                                                                                int a = 3;
                                                                                                                func = [&](){ a++; };
                                                                                                                };

                                                                                                                f();
                                                                                                                func();

                                                                                                                время жизни переменной a, по стандарту языка, кончилось по выходу из f(). Соответственно непонятно к какой перменной будет иметь доступ лямбда.

                                                                                                                P.S. что собственно и описано в пропозале:

                                                                                                                9… If one or more names in the effective capture set are preceded by &, the effect of invoking a closure object, or a copy, after the innermost block scope of the context of the lambda expression has been exited is undefined.
                                                                                                                • 0
                                                                                                                  «никак не отражаются на лямбде» читать как «никак не отражаются на перменных вне оямбды»
                                                                                                • –1
                                                                                                  интересно наблюдать, как с каждым витком развития в с++ пытаются запилить всё больше реально удобных фич lisp'a (буквально наднях читал про «генератор кода», т.н. t4 — по сути: попытка повторить макросы cl)
                                                                                                  • 0
                                                                                                    вы путаете, t4 это для C#
                                                                                                    • 0
                                                                                                      возможно, на истину в последней инстанции не претендую (относительно с++ и с# интерес сугубо созерцательный).
                                                                                                    • +1
                                                                                                      T4 — это ни черта не макросы lisp. t4 — просто текстовый шаблонизатор (в прямом смысле этого слова)/formatter/replacer, не более. Про семантику языка, AST и прочее он не знает.
                                                                                                    • 0
                                                                                                      вот бы еще поддержку делегатов без извращений с шаблонами…

                                                                                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.