Evgenii Legotckoi
Evgenii Legotckoi14 лютого 2018 р. 05:13

Приготування лямбда-функцій на C++ - Частина 1

Мій улюблений інструмент C++ - це лямбда функції, хоча якось мені говорили, що вони здаються страшними. Насправді вони чарівні. Вони значно полегшують написання програм і дозволяють робити досить цікаві рішення.

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

Можливі варіанти синтаксису лямбда функцій

[ capture ] ( params ) mutable exception attribute -> ret { body }
[ capture ] ( params ) -> ret { body }
[ capture ] ( params ) { body }
[ capture ] { body }

Перший варіант є повним, але не забороняється використовувати скорочені варіації запису функцій.

  • capture - список зовнішніх об'єктів, що захоплюються, вони можуть захоплюватися як за посиланням, так і копіюванням.
  • params - список параметрів, що передаються в лямбда функції, дана частина буде аналогічна запису аргументів для звичайних функцій.
  • mutable - використання mutable дозволяє модифікувати копії об'єктів, захоплених копіюванням. У звичайному варіанті вони не модифікуватимуться.
  • exception - забезпечує специфікацію виключення, тобто лямбда функції як і звичайні функції можуть викидати винятки.
  • attribute - забезпечує специфікацію атрибуту, таких атрибутів у специфікації C++ визначено всього два ([[noreturn]], [[carries_dependency]])
  • params - список параметрів, що передаються в лямбда функцію
  • ret - значення лямбда функції, що повертається

Що стосується значення, що повертається, то воно може автоматично виводитися з типу об'єкта, який повертається оператором return. Якщо ж у лямбда-функції відсутня оператор return, то значення, що повертається, буде void.

Функція Лямбда створює безіменний тимчасовий об'єкт унікального безіменного non-union, non-aggregate типу, відомого як тип замикання. Завдяки введенню оператора auto в сучасному стандарті C++ можна оголосити об'єкт лямбда функції досить легко, без прописування оголошення функтора ( * std::function * ) з усіма апраметрами і значеннями, що повертаються, що робить код більш простим і читаним (для досвідченого програміста, звичайно. Безумовно потрібно враховувати те, що новачок швидше запідозрить негаразд, якщо в оголошенні лямбди буде фігурувати std::function але це вже питання практики).

Ось приклад оголошення простий лямбда функції, яка повертатиме тип void , оскільки відсутній хоча б один оператор return .

#include <iostream>

using namespace std;

int main()
{
    auto myLambda = []()
    {
        cout << "Hello World!" << endl;
    };

    myLambda();

    return 0;
}

Відповідно програмний код не скомпілюється, якщо в лямда-функції будуть присутні два і більше оператори return, які повертатимуть об'єкти різних типів, не пов'язаних між собою ієрархією успадкування і не здатні бути приведені до типу базового класу. І навіть, якщо ці об'єкти мають базовий клас, необхідно буде прописати тип значення, що повертається, їм якраз буде покажчик на об'єкт базового класу (в загальному випадку).

Ось приклад коду, який не скомпілюється.

#include <iostream>

using namespace std;

class A
{
public:
    A(){}
};

class B : public A
{
public:
    B(){}
};

class C : public A
{
public:
    C(){}
};

int main()
{
    auto myLambda = [](int type)
    {
        if (type == 0)
        {
            return new B();
        }
        else
        {
            return new C();
        }
    };

    myLambda(0);

    return 0;
}

Потрібно вказати тип значення, що повертається

auto myLambda = [](int type) -> A* // Укажем тип возвращаемого значения
{
    if (type == 0)
    {
        return new B();
    }
    else
    {
        return new C();
    }
};

Також помилка компіляції буде в тому випадку, якщо не вказати тип значення, що повертається і при цьому ви створюєте в купі об'єкт всередині лямбда функції, але в деяких випадках можете повернути покажчик на nullptr. Тобто нижче наступний код не скомпілюється.

#include <iostream>

using namespace std;

class A
{
public:
    A(){}
};


int main()
{
auto myLambda = [](int type)
{
    if (type == 0)
    {
        return new A();
    }
    else
    {
        return nullptr;
    }
};

    myLambda(0);

    return 0;
}

Знову потрібно вказати тип значення, що повертається

auto myLambda = [](int type) -> A* // Укажем тип возвращаемого значения
{
    if (type == 0)
    {
        return new A();
    }
    else
    {
        return nullptr;
    }
};

Справа в тому, що nullptr - це універсальний тип даних, який у якомусь сенсі не є типом даних, оскільки його не можна встановити як тип змінної. Але може бути присвоєний як значення покажчику на об'єкт. Щоб неявне перетворення в даному випадку відбувалося правильно, потрібно також вказати тип значення, що повертається.

Також у наведеному вище прикладі показано, як викликати лямда функцію і передати в неї параметри. Помітили? У цьому прикладі використовується параметр int type , залежно від якого ми повертаємо покажчик на створений об'єкт або nullptr .

Також у лямбда функціях є поняття захоплення змінних. Це означає, що лямбда функція може використовувати не тільки змінні, які передаються їй як параметри, але і будь-які об'єкти, які були оголошені поза лямда-функцією.

Список символів може бути переданий таким чином:

  • **[a,&amp;b]**
    де a захоплена за значенням, а b захоплена за посиланням.
  • **[this]**
    захоплює покажчик
    **this**
    за значенням.
  • **[&amp;]**
    захоплення всіх символів за посиланням
  • **[=]**
    захоплення всіх символів за значенням
  • **[]**
    нічого не захоплює

Для захоплення змінних поговоримо в наступних статтях.

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

Наприклад такий код теж скомпілюється

#include <iostream>

using namespace std;

class A
{
public:
    A(){}
};


int main()
{

    A* myA = [](int type) -> A*
    {
        if (type == 0)
        {
            return new A();
        }
        else
        {
            return nullptr;
        }
    }(0);

    return 0;
}

Тож подумайте, чи скомпілюється наступний програмний код?

int main(){[](){}();}
Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
Ua

Qt - Тест 001. Сигналы и слоты

  • Результат:84бали,
  • Рейтинг балів4
Ua

Qt - Тест 001. Сигналы и слоты

  • Результат:42бали,
  • Рейтинг балів-8
ОК

Qt - Тест 001. Сигналы и слоты

  • Результат:47бали,
  • Рейтинг балів-6
Останні коментарі
ИМ
Игорь Максимов22 листопада 2024 р. 21:51
Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 жовтня 2024 р. 23:37
Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 жовтня 2024 р. 17:19
Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов05 жовтня 2024 р. 16:51
Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas505 липня 2024 р. 20:02
QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Тепер обговоріть на форумі
AH
Abdul Hadi13 лютого 2025 р. 15:21
Are you Looking for best painter services in Qatar? Looking for top painter Services in Qatar? Get high-quality, affordable, and professional painting for homes & offices. Contact expert painters today!
d
dubaicushions13 лютого 2025 р. 15:17
Are Looking for custom swing cushions in Dubai for home decor? Looking for Custom Swing Cushions in Dubai? Get high-quality, weather-resistant, and stylish cushions for your outdoor swing. Order now for comfort & elegance!
d
dubaicustomizedsofa13 лютого 2025 р. 15:11
Are you Looking for a custom sofa in Dubai? Looking for a Custom Sofa in Dubai ? Get high-quality, stylish, and tailor-made sofas to match your space. Order now for comfort, luxury, and perfect design!
b
blinds1211 лютого 2025 р. 16:08
Why Bamboo Blinds Are the Perfect Choice for Your Home When it comes to enhancing the aesthetics and functionality of your living space, choosing the right window treatment is crucial. Bamboo blinds have emerged as a popular choice for homeowners wh…
i
imperial313011 лютого 2025 р. 15:40
How to Select the Right Carpet for Your Bedroom Aesthetic Choosing the perfect carpet for your bedroom involves more than just picking a color or pattern you like. Carpets can transform the ambiance of your space, adding warmth, comfort, and style. How…

Слідкуйте за нами в соціальних мережах