top of page

C++ Dilinde std::optional

  • Writer: Yusuf Hançar
    Yusuf Hançar
  • Aug 11, 2024
  • 10 min read

C++17 ile birlikte dilimize kazandırılan std::optional, modern C++ programlamada esnek ve güvenilir kod yazma imkânı sunan önemli bir araçtır. std::optional, generic programlamanın avantajlarını kullanarak, bir değere sahip olma durumunu ve bu değerin var olup olmadığını kolaylıkla yönetmenize olanak tanır.

Bu sınıf şablonu, bir değeri ya da değersiz bir durumu temsil edebilir. Örneğin, bir std::optional<std::string> türünde bir değişken, bir isim içerebilir ya da içermeyebilir. Bu durum, özellikle bazı özelliklerin isteğe bağlı olduğu veya her durumda mevcut olmasının gereksiz olduğu senaryolar için oldukça kullanışlıdır. Örneğin, bir kişisel veri formunda "orta isim" alanı bazı bireyler için mevcut olabilirken, diğerleri için bu alan boş olabilir. std::optional, bu gibi durumları etkili bir şekilde yönetmeyi sağlar.

std::optional'ın önemli özelliklerinden biri, değere sahip olmayan bir durumun, nesnenin hiç oluşturulmamış olmasıyla eşdeğer olmasıdır. Bu, bellek yönetimi ve güvenliği açısından büyük bir avantaj sağlar çünkü değer içermeyen bir std::optional nesnesi için bu durumun açıkça belirlenmiş olması, programın diğer bölümlerinde güvenilirliği artırır. Ayrıca, std::optional bir pointer sınıfı değildir; aksine, sarmalayıcı bir sınıf olarak, değerlerin mevcut olup olmadığını açıkça ifade eder.

C++17 öncesi Boost.Optional alternatif olarak kullanabiliyordu.


  • Bir std::optional<T> nesnesi değer içerdiğinde, bu değer nesnenin kendisinin bir parçası olarak yer alır ve bu nedenle dinamik bellek tahsisi gerekmez. Bu özellik, std::optional<T>'ın bir pointer değil, bir değer nesnesi olduğunu gösterir; bu nedenle operator*() ve operator->() tanımlı olsa bile, bu sınıfın amacı işaretçi yerine doğrudan bir nesne modellemektir.

    Ek olarak, bir std::optional<T> nesnesi bağlamsal olarak bool türüne dönüştürüldüğünde, bu dönüşüm işlemi nesnenin değer içerip içermediğine bağlıdır. Eğer std::optional<T> bir değer içeriyorsa, dönüşüm true olarak gerçekleşir; eğer değer mevcut değilse, dönüşüm false olarak gerçekleşir. Bu özellik, std::optional<T>'ın durumunu kontrol etmek ve karar mekanizmalarında kullanmak için oldukça kullanışlıdır.

  • std::optional dinamik bir bellek alanı kullanmaması durumu garanti altındadır.

    • std::optional<T> kısaca "sizeof(T) + bool" kadar bir storage kaplar. Ayrıca allignment devreye girdiği unutulmamalıdır.

#include <optional>

template <typename T>
class Optional {};

std::optional nesnesi aşağıdaki koşullarda bir değer içerir:
  • Nesne, T türünde bir değerle veya değer içeren başka bir std::optional değerle başlatılır.


std::optional nesnesi aşağıdaki koşullarda bir değer içermez:
  • Nesne default initialize edilirse,

  • Nesne, "std::nullopt_t" türünde bir değerle veya değer içermeyen std::optional

    nesnesiyle initialize edilirse,

  • reset() üye işlevi çağrılır.



cppreference std::optional örneği ile başlayalım örneklerimize...
#include <iostream>
#include <optional>
#include <string>
 
// optional can be used as the return type of a factory that may fail
std::optional<std::string> create(bool b)
{
    if (b)
    {
        return "Godzilla";
    }

    return {};
}
 
// std::nullopt can be used to create any (empty) std::optional
auto create2(bool b)
{
    return b ? std::optional<std::string>{"Godzilla"} : std::nullopt;
}
 
int main()
{
    std::cout << "create(false) returned " << create(false).value_or("empty") << '\n';
 
    // optional-returning factory functions are usable as conditions of while and if
    if (auto str = create2(true))
    {
        std::cout << "create2(true) returned " << *str << '\n';
    }
}

#include <optional>

int main()
{
    std::optional<int> ix;
    std::optional<std::string> sx;
    std::optional<std::vector<int>> ivx;
}
*****************************     
AÇIKLAMA : 
-> ix, bir int değeri içerebilen veya içermeyen bir std::optional nesnesidir. Başlangıçta bu nesne değersizdir (yani, std::nullopt ile işaretlenmiştir).
-> sx, bir std::string değeri içerebilen veya içermeyen bir std::optional nesnesidir. Başlangıçta bu nesne de değersizdir.
-> ivx, bir std::vector<int> değeri içerebilen veya içermeyen bir std::optional nesnesidir. Başlangıçta bu nesne de değersizdir.
*****************************     

std::optional değere sahip mi değil mi sorgulamasını yapan iki public fonksiyon vardır :
  1. operator bool

  2. has_value


#include <optional>

int main()
{
    std::optional<int> ix{};  // value initialize

    // if (ix.operator bool())
    if (ix) {}
}

#include <optional>

int main()
{
    std::optional<int> ix; // default constructor

    std::cout << (ix.has_value() ? "val" : "nullopt") << "\n";
}

std::optional nesnesinin kurucu işlevine "nullopt" değeri geçilirse boş şekilde hayata başlar.
#include <optional>

int main()
{
    std::optional<int> ix{ nullopt };

    std::cout << (ix.has_value() ? "val" : "nullopt") << "\n";
}

std::optional nesnesinin tuttuğu değere erişim için :
  1. içerik operator fonksiyonu(operator*, operator->)

  2. value() public üye fonksiyonu

  3. value_or() public üye fonksiyonu


#include <optional>

int main()
{
    std::optional<std::string> os{ "smartcode" };
    
    std::cout << *os << "\n";

    *os = "modern cpp";

    std::cout << *os << "\n";
}
*****************************     
AÇIKLAMA : içerik operator fonksiyonu reference döndürür.
*****************************     
CEVAP : 
smartcode
modern cpp
*****************************

#include <optional>

int main()
{
    std::optional<std::string> os{ "smartcode" };
        
    std::cout << "len : " << os->length() << "\n";
}
*****************************     
CEVAP : len : 9
*****************************

#include <optional>

int main()
{
    std::string str{ "smartcode" };
    std::optional<std::string> os{ str };

    std::cout << *os << "\n";
}
*****************************     
AÇIKLAMA : 
*****************************     
CEVAP : smartcode
*****************************

#include <optional>

int main()
{
    std::string str{ "smartcode" };
    std::optional<std::string*> os{ &str };

    **os;  
}
*****************************     
AÇIKLAMA : bir std::optional nesnesi olan os oluşturuluyor ve std::string* türünden bir pointer içeriyor. Bu pointer, str  nesnesinin adresini gösteriyor. &str ifadesi, str nesnesinin adresini alır, bu da bir std::string* türündedir.
std::optional<std::string *> os{ &str }; ifadesi, os nesnesini başlatır ve içerisine bu pointer'ı koyar. Burada os içeren bir std::string* pointer'ı (yani, str nesnesinin adresini) barındıran bir std::optional nesnesidir. **os ifadesi, *os tarafından döndürülen std::string* pointer'ını dereference eder. Bu, str nesnesine doğrudan erişimi sağlar.,

-> os nesnesinin boş olup olmadığını kontrol etmeden **os işlemine geçiliyor. os boş olsaydı (yani içeriğinde bir pointer bulunmasaydı), dereference işlemi geçersiz ve hatalı olurdu.
*****************************     
CEVAP : legal
*****************************

#include <optional>

int main()
{
    std::optional is = 10;
}
*****************************     
AÇIKLAMA : CTAD sayesinde legal
*****************************     

* operator ya da -> operator fonksiyonunu kullandığımızda eğer std::optional nesnesi boş ise exception throw etmez ve tanımsız davranıştır.
#include <optional>

int main()
{
    std::optional<std::string> os;

    try
    {
        auto val = *os;            // undefined behaviour
        auto val1 = os->length();  // undefined behaviour
    }
    catch(const exception& ex)
    {
        std::cout << "exception caught : " << ex.what() << "\n";
    }
}

Sınıfın value() fonksiyonu yine reference semantik ile bizi std::optional'ın sarmaladığı nesneye eriştirir. Ancak std::optional boş ise exception throw eder.
#include <optional>

int main()
{
    std::optional<std::string> os;

    try
    {
        auto val = os.value();            
    }
    //catch(const exception& ex) // aynı
    catch(const bad_optional_access& ex)
    {
        std::cout << "exception caught : " << ex.what() << "\n";
    }
}
*****************************     
CEVAP : bad optional access
*****************************

value_or()
  • std::optional nesnesi bir değeri tutarsa o değeri döndürür yoksa value_or() fonksiyonuna arguman olarak gönderilen değeri döndürür.

  • reference semantiği değil, value semantiktir. value() gibi reference döndürmez, değer döndürür.


int main()
{
    std::optional<std::string> os;

    std::cout << os.value_or("smartcode");
}  
*****************************     
CEVAP :  smartcode
*****************************

int main()
{
    std::optional<std::string> os{ "smartcode" };

    os.value() = "modern cpp";
}  
*****************************     
AÇIKLAMA : reference döndürür.
*****************************     
CEVAP : legal
*****************************

int main()
{
    std::optional<std::string> os{ "smartcode" };

    os.value_or() = "modern cpp";
}  
*****************************     
AÇIKLAMA : reference döndürmez.
*****************************     
CEVAP : syntax error
*****************************

std::optional nesnelere reference tutamaz.
int main()
{
    std::optional<std::string&> os;
}  
*****************************
CEVAP : syntax error
*****************************

std::optional nesnelere reference wrapper tutabilir. (ref, cref... gibi)
#include <iostream>
#include <optional>
#include <functional>

int main()
{
    std::string str{ "cpp" };
    std::optional<std::reference_wrapper<std::string>> os(std::ref(str));

    os->get() += "-17"; // reference_wrapper sınıfının get fonksiyonu

    std::cout << "standart : " << str << "\n";
}  
*****************************
CEVAP : standart : cpp-17
*****************************

  • CTAD ile yazarsak...

#include <iostream>
#include <optional>
#include <functional>

int main()
{
    std::string str{ "cpp" };
    std::optional os = std::ref(str);

    os->get() += "-17";

    std::cout << "standart : " << str << "\n";
} 
*****************************
CEVAP : standart : cpp-17
*****************************

in_place_t türünden in_place helper fonksiyonu
  • utilty başlık dosyasındadır.

class Data {
public :
    Data()
    {
        std::cout << "def ctor\n";
    }

    ~Data()
    {
        std::cout << "dtor\n";
    }

    Data(const Data&)
    {
        std::cout << "copy ctor\n";
    }

    Data(Data&&)
    {
        std::cout << "move ctor \n";
    }
};

int main()
{
    std::optional<Data> op;
}  
*****************************     
AÇIKLAMA : bu şekilde nesne oluşturursak boş bir optional nesnesi olur. 
bu şekilde def ctor edilmiş bir optional nesnesi oluşturmak mümkün değildir.
yani henüz nesne construct edilmedi. bu optional avantajlarındandır
*****************************
CEVAP : 
*****************************

int main()
{
    std::optional<Data> op{ Data{} };
}  
*****************************
CEVAP : 
def ctor
copy ctor
dtor 
dtor
*****************************

int main()
{
    std::optional<Data> op{ Data{} };
}  
*****************************
CEVAP : 
def ctor
move ctor
dtor 
dtor
*****************************

#include <utilty>

int main()
{
    std::optional<Data> op{ std::in_place };
}  
*****************************
CEVAP : 
def ctor
dtor
*****************************

#include <iostream>
#include <string>
#include <vector>
#include <optional>

std::vector<std::string> all_month = {"Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"};

std::vector<std::string> all_day = {"Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"};

class Date {
public:
    Date(int day, int month, int year) : m_day(day), m_month(month), m_year(year) {}

    std::string convert_to_date() const 
    {
        std::string dname = all_day[get_day_of_week()];
        std::string mname = all_month[m_month - 1]; 
        
        return std::to_string(m_day) + " " + mname + " " + 
               std::to_string(m_year) + " " + dname;
    }

    int get_day_of_week() const 
    {
        int day = (14 - m_month) / 12;
        int year = m_year - day;
        int mnt = m_month + 12 * day - 2;
        
        return (m_day + year + year / 4 - year / 100 + year / 400 + (31 * mnt) / 12) % 7;
    }

private:
    int m_day;
    int m_month;
    int m_year;
};

int main() 
{
    std::optional<Date> op{std::in_place, 11, 8, 2024};

    if (op.has_value()) 
    {
        std::cout << op.value().convert_to_date() << "\n";
    } 
    else 
    {
        std::cout << "invalid date!\n";
    }

    return 0;
}
*****************************
CEVAP : 11 Ağustos 2024 Pazar
*****************************

std::make_optional
int main() 
{
    auto op = std::make_optional<Data>();

    auto op1 = std::optional<Data>(std::in_place);

    return 0;
}
*****************************     
AÇIKLAMA : her iki yazımda aynı anlamdadır.
*****************************

int main() 
{
    auto op = std::make_optional<Date>(11, 8, 2024);

    if (op.has_value()) 
    {
        std::cout << op.value().convert_to_date() << "\n";
    } 
    else 
    {
        std::cout << "Geçersiz tarih!\n";
    }

    return 0;
}
*****************************
CEVAP : 11 Ağustos 2024 Pazar
*****************************

int main() 
{
    std::optional<std::string>(std::in_place, 10, 'o');
    auto op = std::make_optional<std::string>(10, 'o');

    return 0;
}

int main() 
{
    std::optional<std::vector<int>>(std::in_place, { 2, 4, 6, 8, 5 });
    std::make_optional<std::vector<int>>({ 2, 4, 6, 8, 5 });

    return 0;
}

reset()
  • std::optional nesnesini boş hale getirmek için kullanılabilir. (nullopt ya da default init edilmesi gibi)


int main() 
{
    std::optional<std::string> op;

    std::cout << std::boolalpha;

    std::cout << "has value : " << op.has_value() << "\n";

    op = "yusuf";

    std::cout << "has value : " << op.has_value() << "\n";

    // optional nesnesinin kendi hayatı devam eder ancak sarmaladığı nesneyi destroy eder.
    op.reset();                  
    //op = nullopt;              // aynı anlamdadır
    //op = optional<string>{};   // aynı anlamdadır. geçici nesne ile
    //op = {};                   // aynı anlamdadır. 

    std::cout << "has value : " << op.has_value() << "\n";

    return 0;
}
*****************************
CEVAP : 
has value : false
has value : true
has value : false
*****************************

emplace modifier fonksiyonu
int main() 
{
    std::optional<Data> op;

    op.emplace();

    std::cout << "main devam ediyor\n";

    return 0;
}
*****************************     
AÇIKLAMA : op.emplace(); çağrıldığında Data nesnesi op içine yerleştirilir, bu işlem Data sınıfının varsayılan yapıcısını çağırır ve "def ctor \n" mesajını yazdırır. Kopya ve taşıma yapıcıları bu durumda çağrılmadı çünkü op.emplace() sadece bir Data nesnesi oluşturup op içine yerleştirdi, taşıma veya kopyalama yapılmadı.
*****************************
CEVAP : 
def ctor
main devam ediyor
dtor
*****************************

#include <iostream>
#include <optional>

class Data {
public:
    Data()
    {
        std::cout << "def ctor \n";
    }

    ~Data()
    {
        std::cout << "dtor \n";
    }

    Data(const Data&)
    {
        std::cout << "copy ctor \n";
    }
    
    Data(Data&&)
    {
        std::cout << "move ctor \n";
    }

    Data(int)
    {
        std::cout << "(int) ctor \n";
    }
};

int main() 
{
    std::optional<Data> op;

    op.emplace();

    std::cout << "main devam ediyor(1)\n";

    op.emplace(10);

    std::cout << "main devam ediyor(2)\n";

    return 0;
}
*****************************     
AÇIKLAMA : op.emplace(10); çağrıldığında mevcut Data nesnesi yok edilir ve Data sınıfının int parametreli yapıcı çağrılır ve "(int) ctor \n" mesajını yazdırır. Bu noktada önceki Data nesnesinin yıkıcı çağrılmıştır, ancak bu kodda yıkıcı mesajı op.emplace(10); çağrısından sonra yazdırıldığı için yıkıcının çıktısı burada yer almıyor. Destructor mesajı param constructor mesajından önce yazdırılmayabilir, çünkü op.emplace(10); çağrısı eski nesnenin yıkılmasını ve yeni nesnenin oluşturulmasını sırasıyla gerçekleştirir ki "dtor \n" mesajı "(int) ctor \n" mesajından sonra görünür.
*****************************
CEVAP : 
def ctor 
main devam ediyor(1)
dtor 
(int) ctor 
main devam ediyor(2)
dtor
*****************************

int main() 
{
    std::optional<Data> op;
    
    for (int idx{}; i < 3; ++idx)
    {
        op.emplace(idx)
    }

    return 0;
}
*****************************     
AÇIKLAMA : her defasından nesne yeniden hayata gelir.
*****************************
CEVAP : 
int val : 0
dtor
int val : 1
dtor
int val : 2
dtor
*****************************

int main() 
{
    std::optional<Data> op;
    
    for (int idx{}; idx < 3; ++i)
    {
        op.emplace(idx)
    }

    op.emplace()

    return 0;
}
*****************************
CEVAP : 
int val : 0
dtor
int val : 1
dtor
int val : 2
dtor
def ctor
dtor
*****************************

std::optional nesneleri karşılaştırma operator'ünün operandı olabilirler.
int main() 
{
    std::optional<int> x = 10;
    std::optional<int> y = 10;

    std::boolalpha(std::cout);

    std::cout << (x == y) << "\n";
    std::cout << (x < y) << "\n";
}
*****************************
CEVAP : 
true
false
*****************************

int main() 
{
    std::optional<int> x = 10;

    std::boolalpha(std::cout);

    std::cout << (x == 10) << "\n";
}
*****************************     
AÇIKLAMA : member template olduğu için bu şekilde de kullanılabilir.
*****************************
CEVAP : true
*****************************

int main() 
{
    std::optional x = "smartcode";

    std::optional<std::string> y;

    std::boolalpha(std::cout);

    std::cout << (y < x) << "\n";
}
*****************************     
AÇIKLAMA : nullopt değerinde olan y daha küçük 
*****************************
CEVAP : true
*****************************

int main() 
{
    std::optional<bool> x;
    std::optional<bool> y{ true };
    std::optional<bool> z{ false };

    std::boolalpha(std::cout);

    std::cout << (x == y) << "\n";
    std::cout << (x == z) << "\n";
    std::cout << (y == z) << "\n";
}
*****************************     
AÇIKLAMA : nullopt değerinde olduğundan
*****************************
CEVAP : 
false
false
false
*****************************

#include <iostream>
#include <optional>

int main() 
{
    int val = 24;

    std::optional<int*> op(&val);

    ++** op;

    std::cout << val << "\n";
}
*****************************
CEVAP : 25
*****************************

#include <iostream>
#include <optional>
#include <string>

bool has_nick(int id) 
{
    return id == 1;
}

std::optional<std::string> get_nick(int id) 
{
    if (has_nick(id)) 
    {
        return "cpp17"; 
    }

    //return std::nullopt;
    //return {};
    return std::nullopt;
}

int main() 
{
    int ids[] = {1, 2, 3}; 
    
    for (int id : ids) 
    {
        std::optional<std::string> nick = get_nick(id);

        if (nick) 
        {
            std::cout << "ID " << id << " and name: " << *nick << "\n";
        } 
        else 
        {
            std::cout << "ID " << id << " name not found\n";
        }
    }

    return 0;
}
*****************************
CEVAP : 
ID 1 and name: cpp17
ID 2 not found
ID 3 not found
*****************************

std::optional<std::string> get_nick(int id)
{
    std::optional<std::string> op;

    if (has_nick(id))
    {
        op = "cpp17";
    }

    return op;
}

bool has_nick(int);

std::optional<std::string> get_nick(int id);

int main() 
{
    // operator bool çağırılır.
    if (std::optional<std::string> op = get_nick(514789)) {}
}

int main() 
{
    if (auto op = get_nick(514789); op) {}
}

int main() 
{
    if (auto op = get_nick(514789); op->length() > 10) {}
}

template <typename C, typename P>
auto find_if(C&& cnt, P&& pred)
{
    auto beg_iter = std::begin(cnt);
    auto end_iter = std::end(cnt);

    auto res = std::find_if(beg_iter, end_iter, pred);

    if (res == end_iter)
    {
        return std::optional<decltype(res)>{};
    }

    return std::optional<decltype(res)>{res};
}

template <typename C, typename V>
auto find(C&& cnt, const V& val)
{
    return find_if(std::forward<C>(cnt),[&val](const auto& elem) 
                   { return elem == val; });
}
*****************************     
AÇIKLAMA : STL std::find_if fonksiyonunun özelleştirilmiş bir versiyonunu yazdık. std::optional kullanarak arama sonuçlarını daha güvenilir bir şekilde temsil edebiliriz .
*****************************

std::optional sınıfında taşıma semantiği
int main() 
{
    std::optional<std::string> op1{ "cpp17" };

    // Kopya semantiği çalışır, op2'nin içinde de "cpp17" bulunur
    auto op2 = op1;   

    // op1 içindeki değeri kontrol ederek length() fonksiyonunu çağırıyoruz
    if (op1)
    {
        std::cout << "op1.length() : " << op1->length() << "\n";        
    }
    else
    {
        std::cout << "op1 is empty\n";
    }

    return 0;
}
*****************************
CEVAP : op1.length() : 5
*****************************

int main() 
{
    std::optional<std::string> op1{ "cpp17" };

    auto op2 = std::move(op1);   

    if (op1)
    {
        std::cout << "op1.length() : " << op1->length() << "\n";        
    }
    else
    {
        std::cout << "op1 is empty\n";
    }

    return 0;
}
*****************************     
AÇIKLAMA : taşıma oldu
*****************************
CEVAP : op1.length() : 0
*****************************

int main() 
{
    std::optional<std::string> op1{ "cpp17" };

    std::optional<std::string> op2 = std::move(*op1);

    std::cout << std::boolalpha << op1.has_value() << "\n";
    std::cout << std::boolalpha << op2.has_value() << "\n";
}
*****************************     
AÇIKLAMA : sadece taşındı destroy edilmedi.
*****************************
CEVAP : 
true
true
*****************************

int main() 
{
    std::optional<std::string> op1{ "smart" };

    std::optional<std::string> op2 = std::move(*op1);

    *op1 = "code";

    std::cout << op1.value();
}
*****************************     
AÇIKLAMA : moved from state deki nesneye yeni değer atanabilir.
*****************************
CEVAP : code
*****************************
std::optional alignment ile ilgili dezavantaj oluşturulabilir.

std::optional C++17 ile birlikte tanıtılan bir türdür ve bir değeri saklayıp saklamayacağına karar verebilen bir kapsayıcıdır. Bir std::optional nesnesi, içinde bir değer olup olmadığını belirten ek bir bayt (bool) ve bu değeri saklayan veri alanı içerir. Bu nedenle, std::optional'ın boyutu, hem içerebileceği veri türünün boyutunu hem de ek bilgileri içerir.


int main() 
{
    std::cout << "sizeof(double) : " << sizeof(double) << "\n";  
} 
*****************************
CEVAP : 8
*****************************

int main() 
{
    cout << "sizeof(std::optional<double>):" << sizeof(std::optional<double>) << "\n";  
}
*****************************     
AÇIKLAMA : bir bool bir de double sığacak kadar bellek alanı içerir std::optional
*****************************
CEVAP : 16
*****************************

struct Smart {
    std::optional<double> d1;
    std::optional<double> d2;
};

struct Code {
    bool val1;
    bool val2;
    double mx;
    double my;
};

int main() 
{
    constexpr auto smrt = sizeof(Smart);    
    constexpr auto cd = sizeof(Code); 
    
    std::cout << smrt << "\n";
    std::cout << cd << "\n";
}
*****************************
CEVAP : 
32
24
*****************************

 
 
 

Recent Posts

See All
C++ Dilinde [[nodiscard]] attribute

C++’ta [[attribute]] (öznitelik) mekanizması, kod hakkında ek bilgi sağlayarak derleyicinin uyarılar vermesine, belirli optimizasyonlar...

 
 
 
C++ Dilinde constinit

C++20'de tanıtılan önemli bir özellik `constinit`'dir; bu özellik, statik depolama süresine sahip değişkenlerin derleme zamanında...

 
 
 

Comments


bottom of page