Məzmuna keç
Educora
İrəli20 dəq10 / 10

Müasir C++: lambdalar, strukturlaşdırılmış bağlamalar və constexpr

C++11–C++20 standartlarının gətirdiyi imkanlarla qısa və etibarlı kod yaz: lambda ifadələri, strukturlaşdırılmış bağlamalar, `const` və `constexpr`.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • C++ standartlarının inkişafını və əsas yeniliklərini təsvir etmək
  • const və constexpr-in fərqini izah etmək
  • Cütləri və xəritə elementlərini strukturlaşdırılmış bağlamalarla açmaq
  • Lambda ifadələri yazmaq və onları STL alqoritmləri ilə işlətmək

C++ 40 ildən artıqdır ki, mövcuddur, amma köhnəlməyib: dil mütəmadi olaraq yenilənir. 1998-ci ildə yazılmış C++ kodu ilə bugünkü kod arasındakı fərq düyməli telefonla smartfon arasındakı fərqə bənzəyir. Bu dərsdə müasir C++ dilinin kodu daha qısa, oxunaqlı və təhlükəsiz edən imkanlarını öyrənəcəksən.

C++ standartları

  1. 1998
    C++98 — ilk beynəlxalq standart

    Dil ISO standartı kimi təsdiqləndi, STL onun bir hissəsi oldu.

  2. 2011
    C++11 — «yeni dil»

    auto, aralıq üzrə for, lambdalar, nullptr, constexpr, std::unique_ptr.

  3. 2014
    C++14 — kiçik təkmilləşmələr

    std::make_unique, auto parametrli lambdalar.

  4. 2017
    C++17

    Strukturlaşdırılmış bağlamalar, std::optional, if constexpr.

  5. 2020
    C++20 — böyük yenilik

    Konseptlər, diapazonlar (ranges), modullar, std::format.

const və constexpr

const dəyişənin ilk qiymətindən sonra dəyişməyəcəyini bildirir, amma bu qiymət proqram işləyərkən də hesablana bilər. constexpr daha sərtdir: qiymət kompilyasiya zamanı məlum olmalıdır. constexpr funksiya sabit arqumentlərlə çağırılanda nəticəni kompilyatorun özü hesablayır — proqram işləyərkən vaxt itirilmir. static_assert isə şərti kompilyasiya zamanı yoxlayır.

C++
#include <iostream>
#include <iterator>

constexpr int cube(int x) {
    return x * x * x;
}

int main() {
    constexpr int volume = cube(3);
    static_assert(volume == 27, "wrong volume");

    int boxes[cube(2)] = {};
    const int players = 4;

    std::cout << "Volume: " << volume << '\n';
    std::cout << "Boxes: " << std::size(boxes) << '\n';
    std::cout << "Players: " << players << '\n';
    return 0;
}
Gözlənilən nəticə
Volume: 27
Boxes: 8
Players: 4
cube(2) kompilyasiya zamanı 8-ə çevrildiyi üçün massivin ölçüsü kimi işlədilə bildi.

Strukturlaşdırılmış bağlamalar

C++17-də gələn strukturlaşdırılmış bağlamalar cütü, korteji və ya sadə strukturu bir sətirdə ayrı-ayrı dəyişənlərə açır: auto [low, high] = ...;. Xüsusilə std::map-i gəzəndə rahatdır: entry.first və entry.second əvəzinə mənalı adlar yazırsan.

C++
#include <iostream>
#include <map>
#include <string>
#include <utility>

std::pair<int, int> minMax(int a, int b) {
    if (a < b) {
        return {a, b};
    }
    return {b, a};
}

int main() {
    auto [low, high] = minMax(9, 4);
    std::cout << low << ' ' << high << '\n';

    std::map<std::string, std::string> capitals = {
        {"Japan", "Tokyo"}, {"Azerbaijan", "Baku"}, {"Georgia", "Tbilisi"}};
    for (const auto& [country, capital] : capitals) {
        std::cout << country << " -> " << capital << '\n';
    }
    return 0;
}
Gözlənilən nəticə
4 9
Azerbaijan -> Baku
Georgia -> Tbilisi
Japan -> Tokyo

Lambda ifadələri

Lambda kodun içində elə yerindəcə yazılan adsız funksiyadır: [tutma](parametrlər) { gövdə }. Kvadrat mötərizələrdə lambdanın ətrafdakı hansı dəyişənləri «tutduğu» göstərilir: [bonus] surətini götürür, [&total] isə istinadla işləyir və orijinalı dəyişə bilir.

C++
#include <iostream>

int main() {
    auto square = [](int x) { return x * x; };

    int bonus = 10;
    auto addBonus = [bonus](int score) { return score + bonus; };

    int total = 0;
    auto addToTotal = [&total](int x) { total += x; };

    std::cout << square(6) << '\n';
    std::cout << addBonus(75) << '\n';
    addToTotal(5);
    addToTotal(7);
    std::cout << "Total: " << total << '\n';
    return 0;
}
Gözlənilən nəticə
36
85
Total: 12

Lambdaların əsl gücü STL alqoritmləri ilə birlikdə üzə çıxır. Aşağıda nəticələri balın azalma sırası ilə çeşidləyir, sonra isə std::count_if ilə neçə şagirdin keçid balını topladığını sayırıq:

C++
#include <algorithm>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

int main() {
    std::vector<std::pair<std::string, int>> results = {
        {"Aysel", 92}, {"Murad", 85}, {"Leyla", 97}, {"Elvin", 78}};

    std::sort(results.begin(), results.end(),
              [](const auto& a, const auto& b) { return a.second > b.second; });

    for (const auto& [name, score] : results) {
        std::cout << name << ": " << score << '\n';
    }

    int passMark = 80;
    auto passed = std::count_if(results.begin(), results.end(),
                                [passMark](const auto& r) { return r.second >= passMark; });
    std::cout << "Passed: " << passed << '\n';
    return 0;
}
Gözlənilən nəticə
Leyla: 97
Aysel: 92
Murad: 85
Elvin: 78
Passed: 3
TutmaMənası
[]heç nə tutmur
[x]x-in surətini
[&x]x-i istinadla
[=]istifadə olunan bütün dəyişənlərin surətini
[&]istifadə olunan bütün dəyişənləri istinadla

Əsas fikirlər

  • C++ müntəzəm yenilənir: C++11, C++14, C++17, C++20 dili daha qısa və təhlükəsiz edib.
  • const qiymətin dəyişməyəcəyini bildirir, constexpr isə onun kompilyasiya zamanı hesablanmasını tələb edir.
  • auto [a, b] = ...; cütü və ya xəritə elementini ayrı dəyişənlərə açır.
  • Lambda: [tutma](parametrlər) { gövdə }; [x] surət, [&x] istinad götürür.
  • Lambdalar std::sort, std::count_if kimi alqoritmlərə öz qaydanı verməyin ən qısa yoludur.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
auto [a, b] = std::pair<int, int>{3, 8}; sətrindən sonra b nəyə bərabərdir?