Menu
Coddy logo textTech

optional, variant, any

Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 89 / 104.

Modern C++, eksik olabilecek değerleri işlemenize, birkaç türden birini barındırmanıza veya herhangi bir türü depolamanıza yardımcı olan <optional>, <variant> ve <any> başlıklarında üç kelime dağarcığı türü sağlar.

std::optional<T>, var olabilecek veya olmayabilecek bir değeri temsil eder - bir istisna fırlatmadan başarısız olabilecek fonksiyonlar için mükemmeldir:

#include <iostream>
#include <optional>

std::optional<int> findIndex(const std::string& str, char c) {
    for (size_t i = 0; i < str.size(); ++i) {
        if (str[i] == c) return i;
    }
    return std::nullopt;  // Değer yok
}

int main() {
    auto result = findIndex("hello", 'l');
    if (result.has_value()) {
        std::cout << "Found at: " << *result << "\n";  // 2
    }
}

std::variant<Types...> herhangi bir zamanda belirtilen türlerden tam olarak birini tutan, tür güvenli (type-safe) bir birleşimdir (union):

#include <iostream>
#include <variant>
#include <string>

int main() {
    std::variant<int, double, std::string> data;
    
    data = 42;
    std::cout << std::get<int>(data) << "\n";
    
    data = "hello";
    if (std::holds_alternative<std::string>(data)) {
        std::cout << std::get<std::string>(data) << "\n";
    }
}

std::any, çalışma zamanında belirlenen herhangi bir türden bir değeri tutabilir. Değeri geri almak için std::any_cast kullanın:

#include <iostream>
#include <any>

int main() {
    std::any value = 10;
    std::cout << std::any_cast<int>(value) << "\n";
    
    value = std::string("text");
    std::cout << std::any_cast<std::string>(value) << "\n";
}

Boş bırakılabilir (nullable) değerler için std::optional'ı, olası türleri derleme zamanında bildiğinizde std::variant'ı ve yalnızca çalışma zamanı tür esnekliğine gerçekten ihtiyaç duyduğunuzda std::any'yi tercih edin.

challenge icon

Görev

Kolay

Modern C++ kelime dağarcığı türlerinin (vocabulary types) gücünü gösteren bir yapılandırma sistemi oluşturalım. Eksik olabilecek, farklı türleri barındırabilen veya çalışma zamanı tür esnekliğine ihtiyaç duyan değerleri işleyen esnek bir ayar yöneticisi oluşturacaksınız.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • ConfigTypes.h: Yapılandırma değer türlerinizi ve yardımcı fonksiyonlarınızı tanımlayın.

    Bir dize alan ve onu bir tam sayı olarak ayrıştırmaya çalışan parseValue adında bir fonksiyon oluşturun. Eğer dize geçerli bir tam sayıyı temsil ediyorsa, std::optional içine sarılmış tam sayıyı döndürün. Ayrıştırma başarısız olursa (dize sayısal olmayan karakterler içeriyorsa), std::nullopt döndürün. Basitlik açısından, bir dizeyi yalnızca rakamlar (ve isteğe bağlı olarak başında bir eksi işareti) içeriyorsa geçerli kabul edin.

    Ayrıca, std::variant kullanarak bir int, bir double veya bir std::string tutabilen Setting adında bir tür takma adı (type alias) oluşturun.

    Son olarak, bir Setting alan ve hangi türü tuttuğunu ve değerini şu formatta açıklayan bir dize döndüren describeSetting adında bir fonksiyon oluşturun:

    • int için: Integer: [value]
    • double için: Double: [value]
    • string için: String: [value]
  • DynamicStore.h: std::any kullanarak basit bir anahtar-değer deposu oluşturun.

    Herhangi bir türdeki değerleri saklayabilen bir DynamicStore sınıfı tanımlayın. Şunlara sahip olmalıdır:

    • Bir dize anahtarı ve bir std::any değeri alan, bunları dahili olarak saklayan bir set metodu (bir std::map kullanın)
    • Bir anahtar alan ve std::any değerini döndüren bir get metodu (anahtar mevcut değilse boş bir std::any döndürün)
    • Anahtar mevcutsa true döndüren bir hasKey metodu
  • main.cpp: Üç girdi okuyun:
    1. Sayı olabilecek bir dize (std::optional'ı test etmek için)
    2. Bir tür göstergesi: int, double veya string
    3. Bu türe karşılık gelen bir değer

    Her üç kelime dağarcığı türünü de gösterin:

    İlk olarak, ilk girdiyle parseValue fonksiyonunuzu kullanın. Eğer bir değer içeriyorsa, Parsed: [value] yazdırın. Boşsa, Parse failed yazdırın.

    İkinci olarak, tür göstergesine göre bir Setting varyantı oluşturun. Tür int ise, değeri bir tam sayı olarak saklayın. double ise, double olarak saklayın. string ise, dize olarak saklayın. Ardından describeSetting fonksiyonunu çağırın ve sonucu yazdırın.

    Üçüncü olarak, bir DynamicStore oluşturun, "status" anahtarı altına "config_loaded" dizesini kaydedin, ardından onu geri alın ve şunu yazdırın: Status: [value]. Değeri çıkarmak için std::any_cast<std::string> kullanın.

Örneğin, 42, int ve 100 girdileriyle:

Parsed: 42
Integer: 100
Status: config_loaded

hello, double ve 3.14 girdileriyle:

Parse failed
Double: 3.14
Status: config_loaded

-15, string ve username girdileriyle:

Parsed: -15
String: username
Status: config_loaded

Gerektiğinde uygun başlık dosyalarını dahil etmeyi unutmayın: <optional>, <variant>, <any>, <string> ve <map>. Varyantınızla çalışmak için std::holds_alternative ve std::get kullanın ve isteğe bağlı (optional) değerinizi kontrol etmek için has_value() veya doğrudan boolean dönüşümü kullanın.

Kopya kağıdı

Modern C++, esnek değerleri işlemek için üç kelime dağarcığı türü sağlar:

std::optional<T>

Var olabilecek veya olmayabilecek bir değeri temsil eder. <optional> başlığını dahil edin:

std::optional<int> findIndex(const std::string& str, char c) {
    for (size_t i = 0; i < str.size(); ++i) {
        if (str[i] == c) return i;
    }
    return std::nullopt;  // Değer yok
}

auto result = findIndex("hello", 'l');
if (result.has_value()) {
    std::cout << *result;  // Değeri almak için referansı çözün
}

std::variant<Types...>

Belirtilen türlerden tam olarak birini tutan, tür açısından güvenli bir birleşimdir (union). <variant> başlığını dahil edin:

std::variant<int, double, std::string> data;

data = 42;
std::cout << std::get<int>(data);

data = "hello";
if (std::holds_alternative<std::string>(data)) {
    std::cout << std::get<std::string>(data);
}

std::any

Çalışma zamanında belirlenen herhangi bir türdeki değeri tutabilir. <any> başlığını dahil edin:

std::any value = 10;
std::cout << std::any_cast<int>(value);

value = std::string("text");
std::cout << std::any_cast<std::string>(value);

Ne zaman kullanılır: Boş bırakılabilir (nullable) değerler için std::optional, olası türler derleme zamanında bilindiğinde std::variant, çalışma zamanı tür esnekliği için std::any.

Kendin dene

#include <iostream>
#include <string>
#include <any>
#include "ConfigTypes.h"
#include "DynamicStore.h"

int main() {
    // Üç girişi oku
    std::string input1;  // Bir sayı olabilecek dize (std::optional testi için)
    std::string typeIndicator;  // Tür göstergesi: int, double veya string
    std::string value;  // Bu türe karşılık gelen değer
    
    std::cin >> input1;
    std::cin >> typeIndicator;
    std::cin >> value;
    
    // TODO: Bölüm 1 - parseValue ile std::optional testi yapın
    // input1 ile parseValue fonksiyonunu kullanın
    // Eğer bir değer içeriyorsa, "Parsed: [value]" yazdırın
    // Eğer boşsa, "Parse failed" yazdırın
    
    
    // TODO: Bölüm 2 - Setting ile std::variant testi yapın
    // typeIndicator temelinde bir Setting varyantı oluşturun
    // Eğer tür "int" ise, değeri tamsayı olarak saklayın
    // Eğer tür "double" ise, değeri double olarak saklayın
    // Eğer tür "string" ise, değeri dize olarak saklayın
    // Ardından describeSetting fonksiyonunu çağırın ve sonucu yazdırın
    
    
    // TODO: Bölüm 3 - DynamicStore ile std::any testi yapın
    // Bir DynamicStore oluşturun
    // "config_loaded" dizesini "status" anahtarı altında saklayın
    // Değeri geri alın ve yazdırın: "Status: [value]"
    // Değeri çıkarmak için std::any_cast<std::string> kullanın
    
    
    return 0;
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler