C++23: std::expected ile hataları işlemenin yeni bir yolu

Adanali

Active member
C++23: std::expected ile hataları işlemenin yeni bir yolu


  1. C++23: std::expected ile hataları işlemenin yeni bir yolu

Veri türü std::eek:ptional C++17’den beri mevcuttur. C++23 ile aşağıda daha ayrıntılı olarak tanıtacağım genişletilmiş tekli bir arayüze sahip olur. Ancak önce veri türüne hızlıca bir göz atalım.

Duyuru









std::eek:ptional


Veri türü std::eek:ptional sonuç doğurabilecek veritabanı sorguları gibi hesaplamalar için çok faydalıdır. Bu veri türü başlık gerektirir <optional>.







Rainer Grimm uzun yıllardır yazılım mimarı, ekip lideri ve eğitim yöneticisi olarak çalışmaktadır. C++, Python ve Haskell programlama dilleri üzerine makaleler yazmayı seviyor ama aynı zamanda özel konferanslarda sık sık konuşmayı da seviyor. Modernes C++ adlı blogunda yoğun bir şekilde C++ tutkusundan bahsediyor.







Çeşitli kurucular ve işlevlerle std::make_optional sadece isteğe bağlı bir nesne olabilir optBir değer tanımlayarak veya tanımlamadan. opt.emplace e eyleminde yer alan değeri oluşturur opt.reset kabın değerini yok eder. bir tane yapabilirsin std::eek:ptional– Kap açıkça bir değeri olup olmadığını sorar veya bunu mantıksal bir ifadeyle test edebilirsiniz. opt.value e değerini döndürür opt.value_or değeri veya varsayılan değeri döndürür. öz opt bir değer içermiyor, çağrı etkinleştirildi opt.value bir std::bad_optional_access-istisna.

İşte basit bir örnek std::eek:ptional:


// optional.cpp

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

std::eek:ptional<int> getFirst(const std::vector<int>& vec){
if ( !vec.empty() ) return std::eek:ptional<int>(vec[0]);
else return std::eek:ptional<int>();
}

int main() {

std::cout << 'n';

std::vector<int> myVec{1, 2, 3};
std::vector<int> myEmptyVec;

auto myInt= getFirst(myVec);

if (myInt){
std::cout << "*myInt: " << *myInt << 'n';
std::cout << "myInt.value(): " << myInt.value() << 'n';
std::cout << "myInt.value_or(2017):" << myInt.value_or(2017) << 'n';
}

std::cout << 'n';

auto myEmptyInt= getFirst(myEmptyVec);

if (!myEmptyInt){
std::cout << "myEmptyInt.value_or(2017):" << myEmptyInt.value_or(2017) << 'n';
}

std::cout << 'n';

}


kullanırım std::eek:ptional fonksiyonda getFirst. getFirst Varsa ilk öğeyi döndürür. Değilse, bir tane alacaksınız std::eek:ptional-Nesne. THE mainfonksiyonun iki vektörü vardır. İkisi de arıyor getFirst kalk ve gir std::eek:ptional– itiraz edin. durumunda myInt nesnenin bir değeri vardır; durumunda myEmptyInt nesnenin hiçbir değeri yoktur. Program değerini görüntüler myInt VE myEmptyInt İLE. myInt.value_or(2017) değeri döndürür ancak myEmptyInt.value_or(2017) varsayılan değeri döndürür.

Duyuru

İşte programın çıktısı:








monadik uzantısı std::eek:ptional


C++23’te olacak std::eek:ptional monadik işlemler etrafında opt.and_then, opt.transform VE opt.or_else büyütülmüş.

  • opt.and_then Belirtilen işlevin çağrılmasının sonucunu eğer varsa döndürür, aksi takdirde boştur std::eek:ptional.
  • opt.transform bir tane verir std::eek:ptional dönüştürülmüş değeri veya boş olanı içeren dönüşler std::eek:ptional.
  • opt.or_else ver onu std::eek:ptional bir değer içeriyorsa veya belirtilen işlevin sonucunu döndürür.
Bu monadik işlemler, işlemleri oluşturmanıza olanak tanır std::eek:ptional:


// optionalMonadic.cpp

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

std::eek:ptional<int> getInt(std::string arg) {
try {
return {std::stoi(arg)};
}
catch (...) {
return { };
}
}


int main() {

std::cout << 'n';

std::vector<std::eek:ptional<std::string>> strings = {"66", "foo", "-5"};

for (auto s: strings) {
auto res = s.and_then(getInt)
.transform( [](int n) { return n + 100;})
.transform( [](int n) { return std::to_string(n); })
.or_else([] { return std::eek:ptional{std::string("Error") }; });
std::cout << *res << ' ';
}

std::cout << 'n';

}


Aralık tabanlı for döngüsü dosya boyunca yinelenir std::vector<std::eek:ptional<std::string>>. İlk önce işlevi dönüştürün getInt her öğeyi bir tamsayıya dönüştürür, ona 100 ekler, tekrar dizeye dönüştürür ve son olarak onu görüntüler. İlk dönüşüm ise int başarısız olursa, dize Error geri döndü ve gösterildi.








std::expected monadik arayüzü zaten destekliyor.

std::expected


std::expected<T, E> iki değerden birini saklamanın bir yolunu sağlar. Bir örneği std::expected her zaman bir değer içerir: türün beklenen değeri T veya türün beklenmeyen değeri E. Bu tür kelime dağarcığı başlığı gerektirir <expected>. Sayesinde std::expected bir değer veya hata döndüren işlevleri uygulayabilirsiniz. Saklanan değer doğrudan beklenen nesnenin kapladığı hafızaya tahsis edilir. Dinamik bellek ayırma yoktur.

std::expected buna benzer bir arayüze sahip std::eek:ptional. Aksine std::eek:ptional Şekerler std::exptected bir hata mesajı döndürün.

Farklı yapıcılarla beklenen bir nesneyi kullanmak mümkündür exp beklenen bir değerle tanımlayın. exp.emplace Eylemin içerdiği değeri oluşturur. bir tane yapabilirsin std::expected– Kap açıkça bir değeri olup olmadığını sorar veya bunu mantıksal bir ifadeyle test edebilirsiniz. exp.value beklenen e değerini döndürür exp.value_or beklenen değeri veya varsayılan değeri döndürür. öz exp beklenmeyen bir değere sahipse çağrı tetiklenir exp.value bir std::bad_expected_access-istisna.

std::unexpected içindeki beklenmeyen değeri temsil eder std::expected kurtarıldı.


// expected.cpp

#include <iostream>
#include <expected>
#include <vector>
#include <string>

std::expected<int, std::string> getInt(std::string arg) {
try {
return std::stoi(arg);
}
catch (...) {
return std::unexpected{std::string(arg + ": Error")};
}
}


int main() {

std::cout << 'n';

std::vector<std::string> strings = {"66", "foo", "-5"};

for (auto s: strings) { // (1)
auto res = getInt(s);
if (res) {
std::cout << res.value() << ' '; // (3)
}
else {
std::cout << res.error() << ' '; // (4)
}
}

std::cout << 'n';

for (auto s: strings) { // (2)
auto res = getInt(s);
std::cout << res.value_or(2023) << ' '; // (5)
}

std::cout << 'n';

}


İşlev getInt her dizeyi bir tam sayıya dönüştürür ve bir değer döndürür std::expected<int, std::string> Geriye doğru. int bekleneni ifade eder ve std::string beklenmeyen değer için. İki aralık tabanlı for döngüsü (satır 1 ve 2) dosya boyunca yinelenir std::vector<std::string>. İlk aralığa dayalı for döngüsü (satır 1), beklenen (satır 3) veya beklenmeyen (satır 4) değeri görüntüler. İkinci aralık tabanlı for döngüsünde (satır 2), 2023’ün beklenen veya varsayılan değeri görüntülenir (satır 5).








std::exptected uygun fonksiyon kompozisyonu için tekli işlemleri destekler: exp.and_then, exp.transform, exp.or_else VE exp.transform_error.

  • exp.and_then varsa belirtilen işlev çağrısının sonucunu veya boş olanı döndürür std::expected.
  • exp.transform bir tane verir std::expected dönüştürülen değeri veya boş olanı içeren döndürür std::expected.
  • exp.or_else verir std::exptected bir değer içeriyorsa veya belirtilen işlevin sonucunu döndürür.
  • exp.transform_error beklenen değerini döndürür std::expected varsa geri dönün. Aksi takdirde, beklenmeyen dönüştürülmüş bir değer vardır. std::expected Geriye doğru.
Aşağıdaki program önceki programa dayanmaktadır optionalMonadic.cpp. Esasen veri türüne sahibim std::eek:ptional Başından sonuna kadar std::expected değiştirildi.


// expectedMonadic.cpp

#include <iostream>
#include <expected>
#include <vector>
#include <string>


std::expected<int, std::string> getInt(std::string arg) {
try {
return std::stoi(arg);
}
catch (...) {
return std::unexpected{std::string(arg + ": Error")};
}
}

int main() {

std::cout << 'n';

std::vector<std::string> strings = {"66", "foo", "-5"};

for (auto s: strings) {
auto res = getInt(s)
.transform( [](int n) { return n + 100; })
.transform( [](int n) { return std::to_string(n); });
std::cout << *res << ' ';
}

std::cout << 'n';

}


Aralık tabanlı for döngüsü dosya boyunca yinelenir std::vector<std::string>. İlk önce işlevi dönüştürün getInt her dizeyi bir tamsayıya dönüştürür, ona 100 ekler, tekrar dizeye dönüştürür ve son olarak onu görüntüler. Bir tamsayıya ilk dönüştürme işlemi başarısız olursa, dize arg + ": Error" geri döndü ve gösterildi.








Sıradaki ne?


Dört ilişkisel kapsayıcı std::flat_map, std::flat_multimap, std::flat_set VE std::flat_multiset C++23’te sıralanmış ilişkisel kapların basit bir alternatifidirler std::map,std::multimap, std::set VE std::multiset. C++23’te bunların bir nedeni var: performans.


(harita)



Haberin Sonu
 
Üst