C++ 20 ile Gelen Yenilikler

C++ 20 ile gelen yenilikler, C++ programlama dilinin son standart revizyonudur. C++ 20, C++ 17’den sonra gelen en büyük güncellemedir ve dilin hem performansını hem de ifade gücünü artıran birçok yeni özellik ve iyileştirme içerir1. Bu makalede, C++ 20 ile gelen bazı önemli yenilikleri örnek kodlar ile açıklayacağız.

C++ 20 ile gelen yeniliklerden bazıları şunlardır:

Kavramlar (Concepts): Kavramlar, bir şablon parametresinin hangi özelliklere sahip olması gerektiğini belirten bir tür kısıtlama mekanizmasıdır. Kavramlar sayesinde, şablon kodlarının okunabilirliği, anlaşılabilirliği ve hata mesajlarının kalitesi artar. Ayrıca, kavramlar, şablonların aşırı yüklenmesini de mümkün kılar. Örneğin, aşağıdaki kodda, sort fonksiyonu, parametresi std::random_access_iterator kavramını sağlayan bir aralık için tanımlanmıştır:

				
					#include <concepts>
#include <algorithm>

template <std::random_access_iterator Iter>
void sort(Iter first, Iter last) {
    std::sort(first, last);
}

				
			
				
					#include <iostream>
#include <concepts>

template <typename T>
concept Arithmetic = std::is_arithmetic<T>::value;

template <Arithmetic T>
T add(T a, T b) {

    return a + b;

}

int main() {

    std::cout << add(5, 10) << std::endl; // Output: 15

    std::cout << add(3.14, 2.71) << std::endl; // Output: 5.85

    // std::cout << add("Hello", "World") << std::endl; // Hata: Belirtilen tür için uygun özellik yok

    return 0;

}
				
			

Modüller (Modules): Modüller, C++’ın geleneksel başlık dosyaları ve kaynak dosyaları yerine kullanabileceği yeni bir kod organizasyonu birimidir. Modüller, kodun yeniden kullanılabilirliğini, bağımlılıklarını ve derleme süresini iyileştirir. Modüller, import ve export anahtar kelimeleri ile tanımlanır ve kullanılır. Örneğin, aşağıdaki kodda, math adında bir modül tanımlanmış ve pow fonksiyonu dışa aktarılmıştır:

				
					// math.ixx
export module math; // modül tanımı

export double pow(double x, int n) { // fonksiyon dışa aktarımı
    double result = 1.0;
    for (int i = 0; i < n; i++) {
        result *= x;
    }
    return result;
}

				
			

Korutinler (Coroutines): Korutinler, bir fonksiyonun birden fazla giriş ve çıkış noktası olabilen ve durumunu koruyabilen genelleştirilmiş alt programlardır. Korutinler, asenkron programlama, veri akışı ve eş zamanlı algoritmalar için yararlıdır. Korutinler, co_await, co_yield ve co_return anahtar kelimeleri ile tanımlanır ve kullanılır. Ayrıca, <coroutine> başlık dosyası, korutinleri destekleyen bazı türler ve kavramlar sağlar. Örneğin, aşağıdaki kodda, generator adında bir korutin türü tanımlanmış ve fibonacci adında bir korutin fonksiyonu kullanılmıştır:

				
					#include <coroutine>
#include <iostream>

template <typename T>
struct generator {
    struct promise_type {
        T value;
        std::suspend_always yield_value(T val) {
            value = val;
            return {};
        }
        std::suspend_always initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        generator get_return_object() { return generator{this}; }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };

    struct iterator {
        std::coroutine_handle<promise_type> coro;
        bool done;
        iterator(std::coroutine_handle<promise_type> c, bool d) : coro(c), done(d) {}
        iterator& operator++() {
            coro.resume();
            done = coro.done();
            return *this;
        }
        bool operator==(iterator const& other) const {
            return done == other.done;
        }
        bool operator!=(iterator const& other) const {
            return !(*this == other);
        }
        T const& operator*() const {
            return coro.promise().value;
        }
        T const* operator->() const {
            return &(coro.promise().value);
        }
    };

    iterator begin() {
        p.resume();
        return {p, p.done()};
    }
    iterator end() {
        return {p, true};
    }
    generator(generator const&) = delete;
    generator(generator&& rhs) : p(rhs.p) {
        rhs.p = nullptr;
    }
    ~generator() {
        if (p) {
            p.destroy();
        }
    }

private:
    explicit generator(promise_type* p) : p(std::coroutine_handle<promise_type>::from_promise(*p)) {}
    std::coroutine_handle<promise_type> p;
};

generator<int> fibonacci(int n) {
    int a = 0;
    int b = 1;
    for (int i = 0; i < n; i++) {
        co_yield a;
        int c = a + b;
        a = b;
        b = c;
    }
}

int main() {
    for (int x : fibonacci(10)) {
        std::cout << x << " ";
    }
    std::cout << "\n";
}

				
			

Biçimlendirme (Formatting): Biçimlendirme, C++’ın <format> başlık dosyası altında sağladığı yeni bir metin biçimlendirme kütüphanesidir. Biçimlendirme, C dilindeki printf fonksiyonundan daha güvenli, daha hızlı ve daha ifade güçlü bir alternatiftir. Biçimlendirme, Python dilindeki str.format metoduna benzer bir sözdizimi kullanır. Örneğin, aşağıdaki kodda, std::format fonksiyonu ile bir metin biçimlendirilmiştir:

				
					#include <format>
#include <iostream>

int main() {
    std::string name = "Alice";
    int age = 25;
    double height = 1.68;
    std::string message = std::format("Hello, {0}. You are {1} years old and {2:.2f} meters tall.", name, age, height);
    std::cout << message << "\n";
}

				
			

Üçlü noktalı sayılar (Three-way comparison): Üçlü noktalı sayılar, C++’ın <compare> başlık dosyası altında sağladığı yeni bir karşılaştırma operatörüdür. Üçlü noktalı sayılar, <=> sembolü ile gösterilir ve iki değerin birbirine göre büyük, küçük veya eşit olup olmadığını tek bir ifade ile belirler. Üçlü noktalı sayılar, sınıflar için de özelleştirilebilir. Örneğin, aşağıdaki kodda, std::strong_ordering türünden bir değer döndüren bir üçlü noktalı sayı operatörü tanımlanmıştır:

				
					#include <compare>
#include <iostream>

struct point {
    int x;
    int y;
    auto operator<=>(const point& other) const {
        if (auto cmp = x <=> other.x; cmp != 0) return cmp;
        return y <=> other.y;
    }
};

int main() {
    point p1 {10, 20};
    point p2 {10, 30};
    auto cmp = p1 <=> p2;
    if (cmp < 0) std::cout << "p1 < p2\n";
    else if (cmp > 0) std::cout << "p1 > p2\n";
    else std::cout << "p1 == p2\n";
}

				
			

C++ 20 ile gelen yenilikler arasında, tasarım edinimleri, sarmalayıcı türler, değişken uzunluklu parametre şablonları, sabit değerlendirme, kapsamlı enum’lar, bit alanları, lambda geliştirmeleri, modüler başlık birimleri, std::span, std::ranges, std::syncstream gibi özellikler bulunmaktadır. Bu özellikler, C++ dilinin hem performansını hem de ifade gücünü artıran birçok yeni özellik ve iyileştirme sunar. Bu makalede, bu yenilikleride örnek kodlar ile açıklayacağız.

Tasarım edinimleri (Designated initializers): Tasarım edinimleri, C++ 20 ile gelen bir özellik olup, bir yapı veya birleşim türündeki bir değişkeni başlatırken, üye adlarını belirterek hangi üyelerin hangi değerlere sahip olacağını açıkça belirtmeyi sağlar3. Tasarım edinimleri, kodun okunabilirliğini ve anlaşılabilirliğini artırır. Ayrıca, tasarım edinimleri, sınıflar için de kullanılabilir, ancak sınıf üyelerinin sırası önemlidir. Örneğin, aşağıdaki kodda, person adında bir yapı türü tanımlanmış ve p1 ve p2 adında iki değişken tasarım edinimleri ile başlatılmıştır:

				
					#include <iostream>
#include <string>

struct person {
    std::string name;
    int age;
    double height;
};

int main() {
    person p1 { .name = "Ali", .age = 20, .height = 1.75 }; // tasarım edinimleri ile yapı başlatma
    person p2 { .height = 1.80, .name = "Veli" }; // sıra önemli değil, atlanan üyeler varsayılan değer alır
    std::cout << "p1: " << p1.name << ", " << p1.age << ", " << p1.height << "\n";
    std::cout << "p2: " << p2.name << ", " << p2.age << ", " << p2.height << "\n";
}

				
			

Sarmalayıcı türler (Wrapper types): Sarmalayıcı türler, C++ 20 ile gelen bir özellik olup, bir değerin türünü değiştirmeden, ona ekstra anlam veya davranış kazandırmayı sağlar. Sarmalayıcı türler, <type_traits> başlık dosyası altında tanımlanmıştır ve std::type_identity, std::remove_cvref ve std::unwrap_ref_decay gibi türler içerir. Sarmalayıcı türler, özellikle şablon programlamada, tür çıkarımını etkilemek veya değiştirmek için yararlıdır. Örneğin, aşağıdaki kodda, std::type_identity sarmalayıcı türü, bir şablon parametresinin türünü korumak için kullanılmıştır:

				
					#include <iostream>
#include <type_traits>

template <typename T>
void print_type(T x) {
    std::cout << "T is " << typeid(T).name() << "\n";
}

template <typename T>
void print_type_identity(std::type_identity_t<T> x) {
    std::cout << "T is " << typeid(T).name() << "\n";
}

int main() {
    int x = 10;
    print_type(x); // T is int
    print_type(10); // T is int
    print_type_identity(x); // T is int
    print_type_identity(10); // T is int
    print_type(&x); // T is int*
    print_type_identity(&x); // T is int*
    print_type(std::move(x)); // T is int
    print_type_identity(std::move(x)); // T is int&&
}

				
			

Değişken uzunluklu parametre şablonları (Variadic template parameters): Değişken uzunluklu parametre şablonları, C++ 20 ile gelen bir özellik olup, bir şablonun birden fazla parametre almasını sağlar. Değişken uzunluklu parametre şablonları, sembolü ile gösterilir ve hem tür hem de değer parametreleri için kullanılabilir. Değişken uzunluklu parametre şablonları, farklı tür veya sayıda parametre alan işlevler veya sınıflar tanımlamak için yararlıdır. Örneğin, aşağıdaki kodda, print adında bir değişken uzunluklu parametre şablonu işlevi tanımlanmış ve kullanılmıştır:

				
					#include <iostream>

template <typename T>
void print(T x) {
    std::cout << x << "\n";
}

template <typename T, typename... Args>
void print(T x, Args... args) {
    std::cout << x << " ";
    print(args...);
}

int main() {
    print(10); // 10
    print("Hello", 3.14, 'A', true); // Hello 3.14 A 1
}

				
			

Sabit değerlendirme (Constexpr evaluation): Sabit değerlendirme, C++ 20 ile gelen bir özellik olup, bir ifadenin veya işlevin derleme zamanında değerlendirilmesini sağlar. Sabit değerlendirme, constexpr veya consteval anahtar kelimeleri ile belirtilir ve derleme zamanında sabit değerler üretmek için kullanılır. Sabit değerlendirme, kodun performansını ve güvenliğini artırır. Örneğin, aşağıdaki kodda, factorial adında bir sabit değerlendirme işlevi tanımlanmış ve kullanılmıştır:

				
					#include <iostream>

consteval int factorial(int n) {
    if (n == 0) return 1;
    return n * factorial(n - 1);
}

int main() {
    constexpr int x = factorial(5); // derleme zamanında hesaplanır
    std::cout << x << "\n"; // 120
}

				
			

Kapsamlı enum’lar (Scoped enums): Kapsamlı enum’lar, C++ 20 ile gelen bir özellik olup, bir numaralandırma türünün üyelerinin kapsamını belirlemeyi sağlar. Kapsamlı enum’lar, enum class veya enum struct anahtar kelimeleri ile tanımlanır ve üyelerine erişmek için :: operatörü kullanılır. Kapsamlı enum’lar, kodun okunabilirliğini ve güvenliğini artırır. Ayrıca, kapsamlı enum’lar, temel türünü belirleyebilir ve diğer türlerle otomatik olarak dönüştürülemez. Örneğin, aşağıdaki kodda, color adında bir kapsamlı enum tanımlanmış ve kullanılmıştır:

				
					#include <iostream>

enum class color : char { red, green, blue }; // kapsamlı enum tanımı, temel türü char

int main() {
    color c = color::red; // kapsamlı enum üyesine erişim
    std::cout << static_cast<char>(c) << "\n"; // kapsamlı enum üyesini char'a dönüştürme
}

				
			

Bit alanları (Bit fields): Bit alanları, C++ 20 ile gelen bir özellik olup, bir yapı veya birleşim türündeki bir üyenin kaç bitlik bir alan kaplayacağını belirlemeyi sağlar. Bit alanları, : operatörü ile tanımlanır ve bit düzeyinde veri depolamak veya işlemek için kullanılır. Bit alanları, kodun verimliliğini artırır. Örneğin, aşağıdaki kodda, screen adında bir yapı türü tanımlanmış ve icon, color, underline ve blink adlı bit alanları içermiştir:

				
					#include <iostream>

struct screen {
    unsigned short icon : 8; // 8 bitlik bir alan
    unsigned short color : 4; // 4 bitlik bir alan
    unsigned short underline : 1; // 1 bitlik bir alan
    unsigned short blink : 1; // 1 bitlik bir alan
};

int main() {
    screen s;
    s.icon = 0b10101010; // ikili sayı sisteminde atama
    s.color = 0xF; // onaltılı sayı sisteminde atama
    s.underline = true; // mantıksal değer atama
    s.blink = false; // mantıksal değer atama
    std::cout << "icon: " << s.icon << "\n"; // 170
    std::cout << "color: " << s.color << "\n"; // 15
    std::cout << "underline: " << s.underline << "\n"; // 1
    std::cout << "blink: " << s.blink << "\n"; // 0
}

				
			

Bit alanlarının temel türü, tamsayı türlerinden biri olmalıdır. Bit alanlarının değerleri, temel türün değer aralığı ile sınırlıdır. Bit alanlarına atanan değerler, bit alanının genişliğine göre kesilir. Örneğin, aşağıdaki kodda, color bit alanı 4 bitlik bir alan olduğu için, 0b11111111 değeri 0b1111 olarak kesilir:

				
					#include <iostream>

struct screen {
    unsigned short icon : 8; // 8 bitlik bir alan
    unsigned short color : 4; // 4 bitlik bir alan
    unsigned short underline : 1; // 1 bitlik bir alan
    unsigned short blink : 1; // 1 bitlik bir alan
};

int main() {
    screen s;
    s.color = 0b11111111; // 8 bitlik bir değer
    std::cout << "color: " << s.color << "\n"; // 15
}

				
			

Bit alanları, aynı temel türden olan bit alanları arasında sıkıştırılabilir. Ancak, farklı temel türden olan bit alanları arasında sıkıştırma yapılamaz. Örneğin, aşağıdaki kodda, a ve b bit alanları aynı temel türden olduğu için, aynı depolama birimini paylaşır. Ancak, c ve d bit alanları farklı temel türden olduğu için, farklı depolama birimlerini kullanır:

				
					#include <iostream>

struct test {
    unsigned short a : 4; // 4 bitlik bir alan
    unsigned short b : 4; // 4 bitlik bir alan
    unsigned int c : 8; // 8 bitlik bir alan
    unsigned int d : 8; // 8 bitlik bir alan
};

int main() {
    std::cout << "sizeof(test): " << sizeof(test) << "\n"; // 6
}

				
			

Bit alanları, aşağıdaki gibi bazı kısıtlamalara sahiptir:

  • Bir bit alanının adresini alamazsınız.
  • Bir bit alanıyla başvuru olmayan const bir başlatma yapamazsınız.
  • Bir bit alanıyla volatile bir başlatma yapamazsınız.
  • Bir bit alanıyla mutable bir başlatma yapamazsınız.
  • Bir bit alanıyla static veya thread_local bir başlatma yapamazsınız.
  • Bir bit alanıyla constexpr veya consteval bir başlatma yapamazsınız.
  • Bir bit alanıyla virtual bir başlatma yapamazsınız.
  • Bir bit alanıyla friend bir başlatma yapamazsınız.
  • Bir bit alanıyla explicit bir başlatma yapamazsınız.
  • Bir bit alanıyla default veya delete bir başlatma yapamazsınız.
  • Bir bit alanıyla noexcept veya override bir başlatma yapamazsınız.
  • Bir bit alanıyla final veya abstract bir başlatma yapamazsınız.
  • Bir bit alanıyla alignas veya alignof bir başlatma yapamazsınız.
  • Bir bit alanıyla typeid veya sizeof bir başlatma yapamazsınız.

Lambda geliştirmeleri (Lambda improvements): Lambda geliştirmeleri, C++ 20 ile gelen bir özellik olup, lambda ifadelerinin tanımını ve kullanımını kolaylaştıran birçok yeni özellik ve iyileştirme içerir. Lambda geliştirmeleri, aşağıdakileri içerir:

  • Lambda şablonları (Lambda templates): Lambda şablonları, bir lambda ifadesinin şablon parametreleri almasını sağlar. Lambda şablonları, [] operatörü ile tanımlanır ve farklı tür veya sayıda parametre alan lambda ifadeleri tanımlamak için yararlıdır. Örneğin, aşağıdaki kodda, add adında bir lambda şablonu tanımlanmış ve kullanılmıştır:
				
					#include <iostream>

int main() {
    auto add = []<typename T>(T x, T y) { return x + y; }; // lambda şablonu tanımı
    std::cout << add(10, 20) << "\n"; // 30
    std::cout << add(3.14, 2.71) << "\n"; // 5.85
}

				
			
  • Genel lambda yakalama (Generic lambda capture): Genel lambda yakalama, bir lambda ifadesinin yakalama listesinde bir değişkenin türünü belirtmeden bir değer yakalamasını sağlar. Genel lambda yakalama, auto anahtar kelimesi ile yapılır ve lambda ifadesinin farklı türdeki değerleri yakalamasına olanak tanır. Örneğin, aşağıdaki kodda, print adında bir lambda ifadesi tanımlanmış ve auto ile bir değer yakalamıştır:
				
					#include <iostream>

int main() {
    auto x = 10;
    auto print = y = x { std::cout << y << " " << z << "\n"; }; // genel lambda yakalama
    print(20); // 10 20
    print(3.14); // 10 3.14
}

				
			
  • Lambda ifadelerinde varsayılan inşa (Default constructibility in lambda expressions): Lambda ifadelerinde varsayılan inşa, bir lambda ifadesinin yakalama listesi boş olduğunda veya sadece = veya & operatörleri içerdiğinde, varsayılan olarak inşa edilebilmesini sağlar. Lambda ifadelerinde varsayılan inşa, lambda ifadelerini bir sınıf veya yapı üyesi olarak tanımlamak veya bir işlev parametresi olarak geçirmek için yararlıdır. Örneğin, aşağıdaki kodda, foo adında bir sınıf tanımlanmış ve bir lambda ifadesini bir üye olarak içermiştir:
				
					#include <iostream>

struct foo {
    auto f =  { std::cout << x << "\n"; }; // varsayılan olarak inşa edilebilir lambda ifadesi
};

int main() {
    foo obj; // foo sınıfından bir nesne oluşturma
    obj.f(10); // foo sınıfının lambda ifadesini çağırma
}

				
			
  • Lambda ifadelerinde paket genişletme (Pack expansion in lambda expressions): Lambda ifadelerinde paket genişletme, bir lambda ifadesinin parametre listesinde veya yakalama listesinde bir değişken uzunluklu parametre paketini genişletmesini sağlar. Lambda ifadelerinde paket genişletme, değişken uzunluklu parametre paketlerini lambda ifadelerine aktarmak için yararlıdır. Örneğin, aşağıdaki kodda, print adında bir değişken uzunluklu parametre şablonu işlevi tanımlanmış ve bir lambda ifadesine bir parametre paketi genişletmesi olarak geçirilmiştir:
				
					#include <iostream>

template <typename... Args>
void print(Args... args) {
    auto f =  { (std::cout << ... << x) << "\n"; }; // lambda ifadesinde paket genişletme
    f(args...); // parametre paketini lambda ifadesine aktarma
}

int main() {
    print(10, 20, 30); // 10 20 30
    print("Hello", "World"); // Hello World
}

				
			

Modüler başlık birimleri (Modular header units): Modüler başlık birimleri, C++ 20 ile gelen bir özellik olup, başlık dosyalarını modüllere dönüştürmeyi sağlar. Modüler başlık birimleri, import anahtar kelimesi ile kullanılır ve başlık dosyalarının derleme süresini azaltır. Modüler başlık birimleri, standart kütüphane başlık dosyaları veya kendi başlık dosyalarınız için kullanılabilir. Örneğin, aşağıdaki kodda, iostream ve vector başlık dosyaları modüler başlık birimleri olarak içe aktarılmıştır:

				
					#include <iostream>
#include <vector>

int main() {
    import std.iostream; // modüler başlık birimi olarak iostream içe aktarma
    import std.vector; // modüler başlık birimi olarak vector içe aktarma
    std::vector<int> v {1, 2, 3};
    for (auto x : v) {
        std::cout << x << " ";
    }
    std::cout << "\n";
}

				
			

std::span (std::span): std::span, C++ 20 ile gelen bir özellik olup, ardışık bir nesne dizisine güvenli ve verimli bir şekilde erişim sağlayan bir görünüm türüdür. std::span, <span> başlık dosyası altında tanımlanmıştır ve bir dizinin, bir vektörün, bir dizinin veya başka bir ardışık veri yapısının bir bölümünü temsil edebilir. std::span, bir veri yapısının kopyasını oluşturmaz, sadece ona bir referans sağlar. Örneğin, aşağıdaki kodda, std::span kullanılarak bir dizinin bir bölümüne erişilmiştir:

				
					#include <iostream>
#include <span>

void print(std::span<int> arr) {
    for (auto x : arr) {
        std::cout << x << " ";
    }
    std::cout << "\n";
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    print(arr); // tüm diziyi yazdırır
    print({arr + 1, 3}); // dizinin bir bölümünü yazdırır
}

				
			

std::ranges (std::ranges): std::ranges, C++ 20 ile gelen bir özellik olup, aralık tabanlı algoritmalar, görünümler ve eylemler sunan bir kütüphanedir. std::ranges, <ranges> başlık dosyası altında tanımlanmıştır ve aralık tabanlı programlamayı kolaylaştırır. std::ranges, aralıkları, bir başlangıç ve bir bitiş yineleyicisi ile tanımlar ve aralıklar üzerinde çeşitli işlemler yapabilir. Örneğin, aşağıdaki kodda, std::ranges kullanılarak bir vektörün bir bölümüne erişilmiştir:

				
					#include <iostream>
#include <ranges>
#include <vector>

void print(std::ranges::range auto&& arr) {
    for (auto x : arr) {
        std::cout << x << " ";
    }
    std::cout << "\n";
}

int main() {
    std::vector<int> v {1, 2, 3, 4, 5};
    print(v); // tüm vektörü yazdırır
    print(v | std::views::drop(2)); // vektörün bir bölümünü yazdırır
}

				
			
				
					#include <iostream>
#include <vector>
#include <ranges>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    auto evenNumbers = numbers | std::views::filter([](int n) { return n % 2 == 0; });

    for (int number : evenNumbers) {
        std::cout << number << " ";
    }
    return 0;
}
				
			

std::syncstream (std::syncstream): std::syncstream, C++ 20 ile gelen bir özellik olup, aynı akışa yazan birden fazla iş parçacığını senkronize etmeyi sağlayan bir akış sınıfıdır. std::syncstream, <syncstream> başlık dosyası altında tanımlanmıştır ve std::osyncstream adında bir sınıf içerir. std::syncstream, bir temel akış nesnesi alır ve ona bir arabellek sağlar. std::syncstream, yıkıcı çağrıldığında veya emit işlevi çağrıldığında, arabelleği temel akışa aktarır. std::syncstream, aynı akışa yazan iş parçacıkları arasında yarış koşullarını önlemek için yararlıdır. Örneğin, aşağıdaki kodda, std::syncstream kullanılarak birden fazla iş parçacığı tarafından std::cout akışına yazılmıştır:

				
					#include <iostream>
#include <syncstream>
#include <thread>
#include <vector>

void print(int id) {
    std::osyncstream out(std::cout); // std::cout akışına bir arabellek sağlar
    out << "Thread " << id << " says hello\n"; // arabelleğe yazma
    out.emit(); // arabelleği std::cout akışına aktarma
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 10; ++i) {
        threads.emplace_back(print, i); // bir iş parçacığı oluşturma
    }
    for (auto& t : threads) {
        t.join(); // bir iş parçacığını beklemek
    }
}

				
			
Yorum Bırakın

E-posta adresiniz yayınlanmayacaktır. Zorunlu alanlar * ile işaretlenmiştir