İçeriğe geç
Educora
İleri20 dk10 / 10

Modern C++: lambdalar, yapısal bağlamalar ve constexpr

C++11'den C++20'ye kadar gelen özelliklerle kısa ve güvenilir kod yaz: lambda ifadeleri, yapısal bağlamalar, `const` ve `constexpr`.

Kendini test et
Bu derste öğreneceklerin
  • C++ standartlarının gelişimini ve temel yeniliklerini anlatmak
  • const ile constexpr arasındaki farkı açıklamak
  • Çiftleri ve harita elemanlarını yapısal bağlamalarla açmak
  • Lambda ifadeleri yazmak ve onları STL algoritmalarıyla kullanmak

C++ 40 yılı aşkın süredir var ama eskimedi: dil düzenli olarak güncelleniyor. 1998'de yazılmış C++ koduyla bugünkü kod arasındaki fark, tuşlu telefonla akıllı telefon arasındaki fark gibidir. Bu derste kodu daha kısa, okunaklı ve güvenli yapan modern C++ özelliklerini öğreneceksin.

C++ standartları

  1. 1998
    C++98 — ilk uluslararası standart

    Dil bir ISO standardı oldu ve STL onun bir parçası hâline geldi.

  2. 2011
    C++11 — “yeni bir dil”

    auto, aralık tabanlı for, lambdalar, nullptr, constexpr, std::unique_ptr.

  3. 2014
    C++14 — küçük iyileştirmeler

    std::make_unique, auto parametreli lambdalar.

  4. 2017
    C++17

    Yapısal bağlamalar, std::optional, if constexpr.

  5. 2020
    C++20 — büyük bir güncelleme

    Kavramlar (concepts), aralıklar (ranges), modüller, std::format.

const ve constexpr

const, bir değişkenin ilk değerinden sonra değişmeyeceğini belirtir; ama bu değer program çalışırken de hesaplanabilir. constexpr daha katıdır: değer derleme sırasında bilinmelidir. Bir constexpr fonksiyon sabit argümanlarla çağrıldığında sonucu derleyicinin kendisi hesaplar; program çalışırken zaman harcanmaz. static_assert ise bir koşulu derleme sırasında denetler.

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;
}
Beklenen çıktı
Volume: 27
Boxes: 8
Players: 4
cube(2) derleme sırasında 8'e dönüştüğü için dizi boyutu olarak kullanılabildi.

Yapısal bağlamalar

C++17 ile gelen yapısal bağlamalar, bir çifti, demeti ya da basit bir yapıyı tek satırda ayrı değişkenlere açar: auto [low, high] = ...;. Özellikle bir std::map dolaşılırken kullanışlıdır: entry.first ve entry.second yerine anlamlı adlar yazarsın.

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;
}
Beklenen çıktı
4 9
Azerbaijan -> Baku
Georgia -> Tbilisi
Japan -> Tokyo

Lambda ifadeleri

Lambda, tam gerektiği yerde yazılan adsız bir fonksiyondur: [yakalama](parametreler) { gövde }. Köşeli parantezler, lambdanın çevredeki hangi değişkenleri “yakaladığını” belirtir: [bonus] bir kopya alır, [&total] ise referansla çalışır ve asıl değişkeni değiştirebilir.

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;
}
Beklenen çıktı
36
85
Total: 12

Lambdaların asıl gücü STL algoritmalarıyla birlikte ortaya çıkar. Aşağıda sonuçları puana göre azalan sırada sıralıyor, ardından std::count_if ile kaç öğrencinin geçme notuna ulaştığını sayıyoruz:

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;
}
Beklenen çıktı
Leyla: 97
Aysel: 92
Murad: 85
Elvin: 78
Passed: 3
YakalamaAnlamı
[]hiçbir şey yakalamaz
[x]x'in bir kopyasını
[&x]x'i referansla
[=]kullanılan tüm değişkenlerin kopyalarını
[&]kullanılan tüm değişkenleri referansla

Önemli noktalar

  • C++ düzenli olarak güncellenir: C++11, C++14, C++17 ve C++20 dili daha kısa ve güvenli hâle getirdi.
  • const değerin değişmeyeceğini belirtir, constexpr ise değerin derleme sırasında hesaplanmasını gerektirir.
  • auto [a, b] = ...; bir çifti ya da harita elemanını ayrı değişkenlere açar.
  • Lambda: [yakalama](parametreler) { gövde }; [x] kopya, [&x] referans alır.
  • Lambdalar, std::sort ve std::count_if gibi algoritmalara kendi kuralını vermenin en kısa yoludur.

Kendini test et

10 soru. Her doğru cevap XP kazandırır.

1 / 10
auto [a, b] = std::pair<int, int>{3, 8}; satırından sonra b kaçtır?