Container Adaptörleri, Ranges, span ve Numeric
STL'nin temel container'larını ve algoritmalarını öğrendin. Şimdi bir adım ilerisine geçiyoruz: container adaptörleri (stack, queue, priority_queue) derinlemesine, C++20 ile gelen devrimsel Ranges kütüphanesi, std::span ile güvenli dizi görünümleri ve <numeric> header'ının güçlü araçları.
1. Container Adaptörleri — Derinlemesine
Container adaptörleri mevcut container'ların üzerine kısıtlanmış bir arayüz sunar. Bir maskeleme gibi düşün: altında vector veya deque çalışır ama sen sadece belirli işlemleri yapabilirsin.
std::stack — LIFO (Last In, First Out)
Tabak yığını düşün: en son koyduğun tabağı en önce alırsın.
#include <stack>
#include <iostream>
#include <vector>
#include <string>
int main() {
// Varsayılan: deque üzerine kurulu
std::stack<int> stk;
stk.push(10);
stk.push(20);
stk.push(30);
std::cout << "Top: " << stk.top() << "\n"; // 30
std::cout << "Size: " << stk.size() << "\n"; // 3
stk.pop(); // 30 çıkar (void döner!)
std::cout << "Top after pop: " << stk.top() << "\n"; // 20
// vector üzerine kurulu stack
std::stack<int, std::vector<int>> vec_stack;
vec_stack.push(1);
vec_stack.push(2);
// Tüm elemanları çıkar
while (!stk.empty()) {
std::cout << stk.top() << " ";
stk.pop();
}
std::cout << "\n";
}Stack ne zaman kullanılır?
Undo/redo sistemleri
Parantez eşleme (bracket matching)
DFS (Depth-First Search) algoritması
Fonksiyon çağrı yığını simülasyonu
Pratik: Parantez Eşleme
#include <stack>
#include <string>
#include <iostream>
#include <unordered_map>
bool is_balanced(const std::string& expr) {
std::stack<char> stk;
std::unordered_map<char, char> pairs = {
{')', '('}, {']', '['}, {'}', '{'}
};
for (char c : expr) {
if (c == '(' || c == '[' || c == '{') {
stk.push(c);
} else if (pairs.count(c)) {
if (stk.empty() || stk.top() != pairs[c]) return false;
stk.pop();
}
}
return stk.empty();
}
int main() {
std::cout << is_balanced("({[]})") << "\n"; // 1 (true)
std::cout << is_balanced("({[})") << "\n"; // 0 (false)
std::cout << is_balanced("((())") << "\n"; // 0 (false)
std::cout << is_balanced("") << "\n"; // 1 (true)
}std::queue — FIFO (First In, First Out)
Banka kuyruğu gibi: ilk gelen ilk hizmet alır.
#include <queue>
#include <iostream>
#include <string>
int main() {
std::queue<std::string> q;
q.push("Ahmet");
q.push("Ayse");
q.push("Mehmet");
std::cout << "On: " << q.front() << "\n"; // Ahmet
std::cout << "Arka: " << q.back() << "\n"; // Mehmet
std::cout << "Size: " << q.size() << "\n"; // 3
q.pop(); // Ahmet çıkar
std::cout << "Yeni on: " << q.front() << "\n"; // Ayse
// Tüm elemanları işle
while (!q.empty()) {
std::cout << "Isleniyor: " << q.front() << "\n";
q.pop();
}
}Queue ne zaman kullanılır?
BFS (Breadth-First Search) algoritması
Görev kuyruğu (task queue)
Mesaj kuyruğu
Yazıcı kuyruğu, destek talebi sistemi
Pratik: Basit Görev Kuyruğu
#include <queue>
#include <iostream>
#include <functional>
#include <string>
struct Task {
std::string name;
std::function<void()> action;
};
int main() {
std::queue<Task> task_queue;
task_queue.push({"Log yaz", [] {
std::cout << " -> Log yazildi\n";
}});
task_queue.push({"Email gonder", [] {
std::cout << " -> Email gonderildi\n";
}});
task_queue.push({"Rapor olustur", [] {
std::cout << " -> Rapor olusturuldu\n";
}});
std::cout << "Gorev kuyrugu isleniyor:\n";
while (!task_queue.empty()) {
auto& task = task_queue.front();
std::cout << "Gorev: " << task.name << "\n";
task.action();
task_queue.pop();
}
}std::priority_queue — Öncelikli Kuyruk
Acil servisteki triaj sistemi gibi: en acil hasta (en yüksek öncelik) ilk muayene edilir.
#include <queue>
#include <iostream>
#include <vector>
#include <string>
int main() {
// Varsayılan: max-heap (en büyük üstte)
std::priority_queue<int> pq;
pq.push(30);
pq.push(10);
pq.push(50);
pq.push(20);
while (!pq.empty()) {
std::cout << pq.top() << " "; // 50 30 20 10
pq.pop();
}
std::cout << "\n";
// Min-heap: en küçük üstte
std::priority_queue<int, std::vector<int>, std::greater<int>> min_pq;
min_pq.push(30);
min_pq.push(10);
min_pq.push(50);
min_pq.push(20);
while (!min_pq.empty()) {
std::cout << min_pq.top() << " "; // 10 20 30 50
min_pq.pop();
}
std::cout << "\n";
}Custom Comparator ile priority_queue
#include <queue>
#include <iostream>
#include <string>
#include <vector>
struct Patient {
std::string name;
int urgency; // Yüksek = daha acil
};
// Custom comparator: urgency'si büyük olan önce
struct ComparePatient {
bool operator()(const Patient& a, const Patient& b) {
return a.urgency < b.urgency; // min → max sıralama, büyük üstte
}
};
int main() {
std::priority_queue<Patient, std::vector<Patient>, ComparePatient> triage;
triage.push({"Ahmet", 2});
triage.push({"Ayse", 5}); // En acil
triage.push({"Mehmet", 1});
triage.push({"Fatma", 4});
std::cout << "Triaj sirasi:\n";
while (!triage.empty()) {
auto& p = triage.top();
std::cout << " " << p.name << " (aciliyet: " << p.urgency << ")\n";
triage.pop();
}
// Ayse(5), Fatma(4), Ahmet(2), Mehmet(1)
}priority_queue ne zaman kullanılır?
Dijkstra algoritması (en kısa yol)
Huffman kodlama
Event scheduling (en erken event ilk)
Top-K problemleri
Adaptör Karşılaştırma Tablosu
| Adaptör | Yapı | Erişim | Varsayılan Container |
|---|---|---|---|
stack | LIFO | top() | deque |
queue | FIFO | front(), back() | deque |
priority_queue | Heap | top() (max/min) | vector |
⚠️ Dikkat:
pop()fonksiyonu hiçbir adaptörde değer dönmez (void). Öncetop()veyafront()ile değeri oku, sonrapop()ile kaldır. Bu tasarım exception safety içindir — kopyalama sırasında hata olursa eleman kaybolmasın.
2. std::span (C++20) — Güvenli Dizi Görünümü
std::span bir sahiplik almayan (non-owning) görünümdür — tıpkı std::string_view'in string'ler için yaptığını diziler için yapar. Ham dizileri, vector'leri, array'leri tek bir tip ile temsil edebilirsin.
Neden span?
C-style fonksiyonlarda dizi ve boyutunu ayrı parametre olarak geçirmek hataya açıktır:
// Tehlikeli — boyut yanlış olabilir
void process(int* data, size_t size) { /* ... */ }
// Güvenli — span hem pointer hem boyutu tutar
#include <span>
void process(std::span<int> data) {
for (int x : data) { // Range-based for çalışır!
std::cout << x << " ";
}
}Temel Kullanım
#include <span>
#include <vector>
#include <array>
#include <iostream>
void print_span(std::span<const int> data) {
std::cout << "[";
for (size_t i = 0; i < data.size(); ++i) {
if (i > 0) std::cout << ", ";
std::cout << data[i];
}
std::cout << "] (size=" << data.size() << ")\n";
}
int main() {
// C dizisi
int arr[] = {1, 2, 3, 4, 5};
print_span(arr); // Otomatik dönüşüm
// std::array
std::array<int, 4> stdarr = {10, 20, 30, 40};
print_span(stdarr);
// std::vector
std::vector<int> vec = {100, 200, 300};
print_span(vec);
// Alt görünüm (subspan)
std::span<int> full(arr);
auto first3 = full.first(3); // İlk 3 eleman
auto last2 = full.last(2); // Son 2 eleman
auto mid = full.subspan(1, 3); // Index 1'den 3 eleman
print_span(first3); // [1, 2, 3]
print_span(last2); // [4, 5]
print_span(mid); // [2, 3, 4]
}Static Extent vs Dynamic Extent
#include <span>
#include <iostream>
// Dynamic extent — boyut çalışma zamanında belli
void dynamic(std::span<int> s) {
std::cout << "Dynamic size: " << s.size() << "\n";
}
// Static extent — boyut derleme zamanında belli (daha verimli)
void fixed(std::span<int, 5> s) {
std::cout << "Fixed size: " << s.size() << "\n";
}
int main() {
int arr[5] = {1, 2, 3, 4, 5};
dynamic(arr); // OK
fixed(arr); // OK — boyut eşleşiyor
std::vector<int> vec = {1, 2, 3};
dynamic(vec); // OK
// fixed(vec); // HATA! vector boyutu derleme zamanında bilinmez
}span ile Güvenli Matris Satır Erişimi
#include <span>
#include <iostream>
#include <vector>
class Matrix {
std::vector<double> data_;
size_t rows_, cols_;
public:
Matrix(size_t r, size_t c) : data_(r * c, 0.0), rows_(r), cols_(c) {}
// Belirli satırı span olarak döndür — kopyalama yok!
std::span<double> row(size_t r) {
return std::span(data_.data() + r * cols_, cols_);
}
std::span<const double> row(size_t r) const {
return std::span(data_.data() + r * cols_, cols_);
}
double& at(size_t r, size_t c) { return data_[r * cols_ + c]; }
size_t rows() const { return rows_; }
size_t cols() const { return cols_; }
};
int main() {
Matrix m(3, 4);
m.at(0, 0) = 1.0; m.at(0, 1) = 2.0; m.at(0, 2) = 3.0; m.at(0, 3) = 4.0;
m.at(1, 0) = 5.0; m.at(1, 1) = 6.0; m.at(1, 2) = 7.0; m.at(1, 3) = 8.0;
auto row0 = m.row(0);
std::cout << "Satir 0: ";
for (double v : row0) std::cout << v << " ";
std::cout << "\n"; // 1 2 3 4
// span üzerinden değiştirme (sahiplik yok ama yazılabilir)
row0[0] = 99.0;
std::cout << "m(0,0) = " << m.at(0, 0) << "\n"; // 99
}💡 İpucu:
spanveriyi kopyalamaz, sadece işaret eder —string_viewile aynı mantık. Bu yüzden span'ın işaret ettiği veri geçerli olmalı. Dangling span (geçersiz belleğe işaret eden span) undefined behavior'dır.
3. C++20 Ranges Kütüphanesi — Devrimsel STL
Ranges, STL algoritmalarının modern, composable ve okunabilir versiyonudur. Geleneksel begin()/end() çiftleri yerine doğrudan container geçersin. Views (görünümler) ile lazy pipeline'lar oluşturabilirsin.
Eski STL vs Ranges
#include <algorithm>
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> nums = {5, 3, 8, 1, 9, 2, 7, 4, 6};
// === Eski yol: iterator çifti ===
std::sort(nums.begin(), nums.end());
auto it = std::find(nums.begin(), nums.end(), 7);
// === Yeni yol: ranges ===
std::vector<int> nums2 = {5, 3, 8, 1, 9, 2, 7, 4, 6};
std::ranges::sort(nums2); // Doğrudan container
auto it2 = std::ranges::find(nums2, 7); // Daha temiz
// ranges ile projeksiyonlar (projection)
struct Student {
std::string name;
int grade;
};
std::vector<Student> students = {
{"Ayse", 90}, {"Mehmet", 75}, {"Fatma", 95}, {"Ali", 80}
};
// grade'e göre sırala — lambda yerine projection!
std::ranges::sort(students, {}, &Student::grade);
// {} = varsayılan comparator (less), &Student::grade = projection
for (auto& s : students) {
std::cout << s.name << ": " << s.grade << "\n";
}
}💡 İpucu: Ranges'ın en güçlü özelliği projection desteğidir. Lambda yazmadan struct'ın hangi alanına göre işlem yapılacağını belirtebilirsin.
Views — Lazy Pipeline'lar
Views veriyi kopyalamaz — sadece dönüşüm kurallarını tanımlar. Veriye erişildiğinde (iterate edildiğinde) dönüşüm uygulanır. Bu yüzden lazy (tembel) çalışır.
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Çift olanları filtrele, karelerini al, ilk 3'ü seç
auto result = nums
| std::views::filter([](int n) { return n % 2 == 0; }) // 2,4,6,8,10
| std::views::transform([](int n) { return n * n; }) // 4,16,36,64,100
| std::views::take(3); // 4,16,36
for (int x : result) {
std::cout << x << " ";
}
std::cout << "\n"; // 4 16 36
// Hiçbir ara container oluşturulmadı!
// Her eleman pipeline'dan geçerken teker teker dönüştürüldü
}🎯 Analoji — Fabrika Üretim Hattı: Views'ı bir fabrika üretim hattı gibi düşün. Hammadde (veri) bandın bir ucundan girer, her istasyon (view) bir işlem yapar ve sonunda ürün çıkar. Ama üretim hattı boşta çalışmaz — sadece ürün istendiğinde (iterate) çalışır.
Yaygın View Türleri
#include <ranges>
#include <vector>
#include <iostream>
#include <string>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// filter: koşula uyan elemanlar
for (int x : v | std::views::filter([](int n) { return n > 5; })) {
std::cout << x << " "; // 6 7 8 9 10
}
std::cout << "\n";
// transform: her elemanı dönüştür
for (int x : v | std::views::transform([](int n) { return n * 10; })) {
std::cout << x << " "; // 10 20 30 40 50 60 70 80 90 100
}
std::cout << "\n";
// take / drop: baştan al / baştan atla
for (int x : v | std::views::take(3)) {
std::cout << x << " "; // 1 2 3
}
std::cout << "\n";
for (int x : v | std::views::drop(7)) {
std::cout << x << " "; // 8 9 10
}
std::cout << "\n";
// reverse: tersine çevir
for (int x : v | std::views::reverse) {
std::cout << x << " "; // 10 9 8 7 6 5 4 3 2 1
}
std::cout << "\n";
// iota: sayı üretici (sonsuz veya sınırlı)
for (int x : std::views::iota(1, 6)) {
std::cout << x << " "; // 1 2 3 4 5
}
std::cout << "\n";
// keys / values: map benzeri container'lar için
std::vector<std::pair<std::string, int>> scores = {
{"Ayse", 90}, {"Ali", 85}, {"Veli", 70}
};
for (auto& name : scores | std::views::keys) {
std::cout << name << " "; // Ayse Ali Veli
}
std::cout << "\n";
}Pipeline Zincirleme
#include <ranges>
#include <vector>
#include <iostream>
#include <string>
struct Employee {
std::string name;
std::string department;
double salary;
};
int main() {
std::vector<Employee> employees = {
{"Ali", "IT", 15000},
{"Ayse", "HR", 12000},
{"Mehmet", "IT", 18000},
{"Fatma", "IT", 22000},
{"Veli", "HR", 11000},
{"Zeynep", "Finance", 16000},
};
// IT departmanındaki 15K+ maaş alanların isimlerini al
auto it_high_earners = employees
| std::views::filter([](const Employee& e) {
return e.department == "IT";
})
| std::views::filter([](const Employee& e) {
return e.salary > 15000;
})
| std::views::transform([](const Employee& e) {
return e.name + " (" + std::to_string(static_cast<int>(e.salary)) + " TL)";
});
std::cout << "IT yuksek maaslilar:\n";
for (const auto& info : it_high_earners) {
std::cout << " " << info << "\n";
}
// Mehmet (18000 TL)
// Fatma (22000 TL)
}View Hızlı Referans Tablosu
| View | Açıklama | Örnek |
|---|---|---|
filter | Koşula uyanları seç | views::filter(pred) |
transform | Her elemanı dönüştür | views::transform(fn) |
take(n) | İlk n eleman | views::take(5) |
drop(n) | İlk n'i atla | views::drop(3) |
reverse | Ters sıra | views::reverse |
iota(a,b) | [a,b) sayı üret | views::iota(1,10) |
keys | Pair/tuple'ın ilk elemanı | views::keys |
values | Pair/tuple'ın ikinci elemanı | views::values |
enumerate (C++23) | İndex + değer çifti | views::enumerate |
zip (C++23) | Birden fazla range'i birleştir | views::zip(r1,r2) |
split | Ayırıcıya göre böl | views::split(',') |
join | İç içe range'leri düzleştir | views::join |
take_while | Koşul sağlandıkça al | views::take_while(pred) |
drop_while | Koşul sağlandıkça atla | views::drop_while(pred) |
⚠️ Dikkat: Views lazy olduğu için yan etkili (side-effect) lambda'larla kullanırken dikkatli ol. Aynı view'ı iki kez iterate edersen lambda iki kez çalışır. View'lar sonucu cache'lemez.
4. <numeric> Header — Matematiksel Algoritmalar
<numeric> header'ı sayısal hesaplamalar için güçlü algoritmalar sunar. <algorithm>'dan ayrıdır çünkü matematiksel operasyonlara odaklanır.
std::accumulate — Biriktirme
#include <numeric>
#include <vector>
#include <iostream>
#include <string>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
// Toplam
int sum = std::accumulate(nums.begin(), nums.end(), 0);
std::cout << "Toplam: " << sum << "\n"; // 15
// Çarpım (custom binary op)
int product = std::accumulate(nums.begin(), nums.end(), 1,
std::multiplies<int>());
std::cout << "Carpim: " << product << "\n"; // 120
// String birleştirme
std::vector<std::string> words = {"Merhaba", " ", "Dunya", "!"};
std::string sentence = std::accumulate(words.begin(), words.end(),
std::string());
std::cout << sentence << "\n"; // Merhaba Dunya!
}std::reduce (C++17) — Paralel Toplama
reduce, accumulate'in paralel çalışabilen versiyonudur. Sıralama garantisi vermez ama çok çekirdekli işlemcilerde çok daha hızlı olabilir:
#include <numeric>
#include <vector>
#include <iostream>
#include <execution> // Paralel politikalar
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Sıralı reduce
int sum = std::reduce(nums.begin(), nums.end(), 0);
std::cout << "Reduce: " << sum << "\n"; // 55
// Paralel reduce (C++17 execution policy)
// int par_sum = std::reduce(std::execution::par,
// nums.begin(), nums.end(), 0);
// Not: Paralel execution derleyici ve OS desteği gerektirir
}⚠️ Dikkat:
accumulatesoldan sağa sıralı çalışır.reducesıralama garantisi vermez — bu yüzden floating-point toplamada farklı sonuçlar verebilir.
std::partial_sum — Kümülatif Toplam
#include <numeric>
#include <vector>
#include <iostream>
#include <iterator>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
std::vector<int> result(nums.size());
std::partial_sum(nums.begin(), nums.end(), result.begin());
// result: {1, 3, 6, 10, 15} (her eleman = o noktaya kadar toplam)
std::cout << "Kumulatif toplam: ";
for (int x : result) std::cout << x << " ";
std::cout << "\n";
// Kümülatif çarpım
std::partial_sum(nums.begin(), nums.end(), result.begin(),
std::multiplies<int>());
// result: {1, 2, 6, 24, 120}
std::cout << "Kumulatif carpim: ";
for (int x : result) std::cout << x << " ";
std::cout << "\n";
}std::adjacent_difference — Ardışık Farklar
#include <numeric>
#include <vector>
#include <iostream>
int main() {
std::vector<int> data = {1, 3, 6, 10, 15};
std::vector<int> diffs(data.size());
std::adjacent_difference(data.begin(), data.end(), diffs.begin());
// diffs: {1, 2, 3, 4, 5} (ilk eleman aynı, sonrakiler fark)
std::cout << "Farklar: ";
for (int x : diffs) std::cout << x << " ";
std::cout << "\n";
}std::inner_product — İç Çarpım
#include <numeric>
#include <vector>
#include <iostream>
int main() {
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {4, 5, 6};
// İç çarpım: 1*4 + 2*5 + 3*6 = 32
int dot = std::inner_product(a.begin(), a.end(), b.begin(), 0);
std::cout << "Ic carpim: " << dot << "\n"; // 32
// Custom op: toplam yerine max, çarpım yerine toplam
int result = std::inner_product(a.begin(), a.end(), b.begin(), 0,
[](int x, int y) { return std::max(x, y); }, // accumulate op
[](int x, int y) { return x + y; }); // combine op
// max(0, 1+4, 2+5, 3+6) = max(0, 5, 7, 9) = 9
std::cout << "Custom: " << result << "\n"; // 9
}std::iota — Artan Seri Doldurma
#include <numeric>
#include <vector>
#include <iostream>
#include <list>
int main() {
std::vector<int> v(10);
std::iota(v.begin(), v.end(), 1); // 1, 2, 3, ..., 10
for (int x : v) std::cout << x << " ";
std::cout << "\n";
// Index dizisi oluşturma (sıralama için)
std::vector<int> indices(5);
std::iota(indices.begin(), indices.end(), 0); // 0, 1, 2, 3, 4
}std::gcd ve std::lcm (C++17)
#include <numeric>
#include <iostream>
int main() {
// EBOB (En Büyük Ortak Bölen)
std::cout << "gcd(12, 18) = " << std::gcd(12, 18) << "\n"; // 6
std::cout << "gcd(7, 13) = " << std::gcd(7, 13) << "\n"; // 1
// EKOK (En Küçük Ortak Kat)
std::cout << "lcm(4, 6) = " << std::lcm(4, 6) << "\n"; // 12
std::cout << "lcm(7, 13) = " << std::lcm(7, 13) << "\n"; // 91
// Birden fazla sayı için: fold expression veya accumulate
auto multi_gcd = [](auto... args) {
return (... , std::gcd(args...)); // Fold expression C++17
};
// Veya basitçe:
int g = std::gcd(std::gcd(12, 18), 24); // gcd(6, 24) = 6
std::cout << "gcd(12, 18, 24) = " << g << "\n";
}std::midpoint ve std::lerp (C++20)
#include <numeric>
#include <cmath>
#include <iostream>
int main() {
// Taşma-güvenli orta nokta hesaplama
int a = 2'000'000'000, b = 2'000'000'000;
// (a + b) / 2 → OVERFLOW!
// std::midpoint(a, b) → güvenli
std::cout << "midpoint: " << std::midpoint(a, b) << "\n"; // 2000000000
// Pointer midpoint
int arr[] = {1, 2, 3, 4, 5};
int* mid = std::midpoint(arr, arr + 4); // arr + 2 = &arr[2]
std::cout << "midpoint ptr: " << *mid << "\n"; // 3
// lerp: lineer interpolasyon
double start = 0.0, end = 100.0;
std::cout << "lerp(0, 100, 0.0) = " << std::lerp(start, end, 0.0) << "\n"; // 0
std::cout << "lerp(0, 100, 0.5) = " << std::lerp(start, end, 0.5) << "\n"; // 50
std::cout << "lerp(0, 100, 1.0) = " << std::lerp(start, end, 1.0) << "\n"; // 100
std::cout << "lerp(0, 100, 0.3) = " << std::lerp(start, end, 0.3) << "\n"; // 30
}Numeric Hızlı Referans
| Fonksiyon | Ne yapar | Header |
|---|---|---|
accumulate | Sıralı biriktirme | <numeric> |
reduce (C++17) | Paralel biriktirme | <numeric> |
partial_sum | Kümülatif toplam | <numeric> |
adjacent_difference | Ardışık farklar | <numeric> |
inner_product | İç çarpım | <numeric> |
iota | Artan seri | <numeric> |
gcd (C++17) | En büyük ortak bölen | <numeric> |
lcm (C++17) | En küçük ortak kat | <numeric> |
midpoint (C++20) | Taşma-güvenli orta | <numeric> |
lerp (C++20) | Lineer interpolasyon | <cmath> |
5. Hepsini Birleştiren Pratik
Tüm konuları birleştiren bir örnek: log dosyası analizi.
#include <iostream>
#include <vector>
#include <string>
#include <ranges>
#include <numeric>
#include <algorithm>
#include <stack>
#include <queue>
struct LogEntry {
std::string timestamp;
std::string level; // INFO, WARN, ERROR
std::string message;
int response_ms;
};
int main() {
std::vector<LogEntry> logs = {
{"10:01", "INFO", "User login", 120},
{"10:02", "ERROR", "DB connection", 5000},
{"10:03", "INFO", "Page view", 45},
{"10:04", "WARN", "Slow query", 1200},
{"10:05", "ERROR", "Timeout", 8000},
{"10:06", "INFO", "API call", 200},
{"10:07", "WARN", "Memory high", 300},
{"10:08", "INFO", "Cache hit", 5},
{"10:09", "ERROR", "Disk full", 0},
{"10:10", "INFO", "Health check", 10},
};
// 1. Ranges: ERROR log'larını filtrele
std::cout << "=== ERROR Logs ===\n";
auto errors = logs
| std::views::filter([](const LogEntry& e) {
return e.level == "ERROR";
});
for (const auto& e : errors) {
std::cout << e.timestamp << " - " << e.message << "\n";
}
// 2. Ranges: Response sürelerini al, 100ms üstünü filtrele
auto slow_times = logs
| std::views::filter([](const LogEntry& e) {
return e.response_ms > 100;
})
| std::views::transform(&LogEntry::response_ms);
std::cout << "\n=== Yavas Istekler (>100ms) ===\n";
for (int ms : slow_times) {
std::cout << ms << "ms ";
}
std::cout << "\n";
// 3. Numeric: Ortalama response süresi
std::vector<int> times;
std::ranges::transform(logs, std::back_inserter(times),
&LogEntry::response_ms);
double avg = static_cast<double>(
std::accumulate(times.begin(), times.end(), 0)) / times.size();
std::cout << "\nOrtalama response: " << avg << "ms\n";
// 4. Partial sum: Kümülatif response
std::vector<int> cumulative(times.size());
std::partial_sum(times.begin(), times.end(), cumulative.begin());
std::cout << "Kumulatif: ";
for (int x : cumulative) std::cout << x << " ";
std::cout << "\n";
// 5. Priority queue: En yavaş 3 isteği bul (min-heap)
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap;
for (const auto& log : logs) {
min_heap.push(log.response_ms);
if (min_heap.size() > 3) min_heap.pop(); // En küçüğü çıkar
}
std::cout << "\nEn yavas 3 istek: ";
std::vector<int> top3;
while (!min_heap.empty()) {
top3.push_back(min_heap.top());
min_heap.pop();
}
std::ranges::sort(top3, std::greater{});
for (int ms : top3) std::cout << ms << "ms ";
std::cout << "\n";
// 6. Stack: Son 3 hata mesajını ters sırada yazdır
std::stack<std::string> error_stack;
for (const auto& e : errors) {
error_stack.push(e.message);
}
std::cout << "\nSon hatalar (ters sira):\n";
while (!error_stack.empty()) {
std::cout << " " << error_stack.top() << "\n";
error_stack.pop();
}
}Özet
Container adaptörleri (stack, queue, priority_queue) mevcut container'lar üzerine LIFO, FIFO ve heap arayüzü sunar —
pop()her zaman void döner, öncetop()/front()ile oku`std::span` (C++20) sahiplik almadan dizi görünümü sağlar — C dizisi, vector, array hepsini tek tip ile kabul edebilirsin,
string_view'in diziler için versiyonuRanges (C++20) STL algoritmalarını modernleştirir: doğrudan container geçme, projection desteği ve
|operatörü ile lazy view pipeline'ları oluşturmaViews veriyi kopyalamaz, lazy çalışır —
filter,transform,take,drop,reversezincirlenerek güçlü pipeline'lar oluşturulur`<numeric>` header'ı:
accumulate/reduce(toplama),partial_sum(kümülatif),gcd/lcm(EBOB/EKOK),midpoint(güvenli orta nokta),lerp(interpolasyon) gibi matematiksel araçlar sunar
AI Asistan
Sorularını yanıtlamaya hazır