Giriş
Bu sınıf C++17 ile standarda girdi. Daha önceki derleyicilerde kullanmak istersek şu satırı dahil ederiz.
C++14 - Tanımlama
Açıklaması şöyle.
Örnek - template
Yani T tipi incomplete olduğu için template içinde kullanılamaz. Şöyle yapamayız.
Ku kod derlenmez. Sebebi yine aynı şekilde Type tipi abstract olduğu için büyüklüğünün bilinmemesi.
C++14 ile gelen incomplete type kuralı geçerli değil. Şöyle yaparız.
Açıklaması şöyle. Yani std::optional T tipinin alignment kurallarına uymalı.
İçinde nesne olmayan optional yaratır.
Örnek
Şöyle yaparız.
Şöyle yaparız
Açıklaması şöyle
Şöyle yaparız.
Şöyle yaparız.
operator* metodu
Örnek
İçinde nesne olmayan optional sınıfına erişmek tanımsız (undefined) davranıştır. Exception fırlatmaz. Şu kod hatalı.
Bu sınıf C++17 ile standarda girdi. Daha önceki derleyicilerde kullanmak istersek şu satırı dahil ederiz.
#include <experitmental/optional>
Bu sınıfı kullanırken std::nullopt'ye de ihtiyaç oluyor.C++14 - Tanımlama
Açıklaması şöyle.
Class template optional imposes little requirements on T: it has to be either an lvalue reference type, or a complete object type satisfying the requirements of Destructible.
Yani T tipi incomplete olduğu için template içinde kullanılamaz. Şöyle yapamayız.
template <typename T>
struct node {
std::experimental::optional<node<T>> next;
T data;
};
Sebebi ise optional içinde T tipinin büyüklüğü kadar bellek alanının ayrılması. Kodu şuna benzer. Eğer T tipi incomplete ise bu kod derlenmez.template <class T>
struct optional
{
bool _containsValue;
char _buffer[ sizeof( T ) ];
};
Ya da kodu şuna benzer. Neticede T tipi için yeterli bellek alanının ayrılması gerekir.template <typename T>
struct optional
{
std::aligned_storage_t<sizeof(T), alignof(T)> _data;
bool _set;
};
Örnek - abstract classKu kod derlenmez. Sebebi yine aynı şekilde Type tipi abstract olduğu için büyüklüğünün bilinmemesi.
struct Type {
virtual bool func(const std::string& val) const noexcept = 0;
}
// in main
optional<Type> = some_function_returning_optional_type();
C++17 - TanımlamaC++14 ile gelen incomplete type kuralı geçerli değil. Şöyle yaparız.
template<typename T>
auto test()
{
auto opt = std::optional<T>{T{}};
...
}
test<int>();
test<double>();
test<std::string>();
AlignmentAçıklaması şöyle. Yani std::optional T tipinin alignment kurallarına uymalı.
Constructor23.6.3 Class template optional(...) The contained value shall be allocated in a region of the optional storage suitably aligned for the type T.
İçinde nesne olmayan optional yaratır.
Örnek
Şöyle yaparız.
std::optional<T> t; // initially empty
ÖrnekŞöyle yaparız
optional<Big> ob{emplace, "1"}; // calls Big{"1"} in place (no moving)
optional<Big> oc{emplace}; // calls Big{} in place (no moving)
optional<Big> od{}; // creates a disengaged optional
Constructor - std::in_place + Args
İmzası şöyletemplate< class... Args >
explicit optional( std::in_place_t, Args&&... args );
in_place construction için kullanılır. Şöyle yaparız.std::optional<std::vector<int>> x{std::in_place, {1,2,3,4,5}}; // OK
Şu kod derlenmiyor ancak ne yapmak lazım bilmiyorum.std::optional<std::vector<int const>> y{std::in_place, {1,2,3,4,5}}; // error!
Copy ConstructorAçıklaması şöyle
...shall be defined as deleted unless is_copy_constructible_v<T> is true.
Move Constructor
Açıklaması şöyle
ÖrnekAçıklaması şöyle
...shall not participate in overload resolution unless is_move_constructible_v<T> is true.
Örnek
Şöyle yaparız.
Move işlemi sonunda primitive tip varsa foo halen dolu görünebilir. Şöyle yaparız.
Şöyle yaparız.
std::optional<X> o1;
std::optional<X> o2(std::move(o1));
ÖrnekMove işlemi sonunda primitive tip varsa foo halen dolu görünebilir. Şöyle yaparız.
std::optional<int> foo{ 0 };
std::optional<int> bar{ std::move(foo) };
std::cout << std::boolalpha
<< foo.has_value() << '\n' // true
<< bar.has_value() << '\n'; // true
emplace metoduŞöyle yaparız.
std::optional<int> x;
x.emplace(3);
ÖrnekŞöyle yaparız.
// now we're ready to create the T value
t.emplace(foo, bar); // constructs the T with foo, bar as args
operator-> metodu
Bu operator kullanılmadan önce std::optional nesnesinin dolu olması gerekir.
Örnek
Şu kod tanımsız davranışa (UB) sebep olur
std::optional<std::string> so;
std::cout << so->size() << std::endl;
std::cout << so.has_value();
Örnek
İçinde nesne olmayan optional sınıfına erişmek tanımsız (undefined) davranıştır. Exception fırlatmaz. Şu kod hatalı.
optional<int> t{}; // nullopt (empty) by default
cout << *t << endl;
Örnek
Adresin hep aynı olup olmaması konusu belirsiz. Şu kod undefined behavior'a sebep olabilir.
Örnek
Şöyle yaparız.
Şöyle yaparız.
Diğer seçenekler
Eğer elimizde std::optional yoksa, ve boost::optional kullanmak istemiyorsak şöyle yapabiliriz.
1. unique_ptr kullanabiliriz.
Şöyle yaparız.
2. std::pair kullanılabilir.
Örnek
Şöyle yaparız.
Şöyle yaparız.
3. Eski usul kodlarız.
Yani şöyle kodlayacağımıza
template<typename T>
auto test()
{
auto opt = std::optional<T>{T{}};
auto* ptr = &*opt;
opt.reset();
opt = T{};
assert(ptr == &*opt); // Can this assert fail?
}
value_or metoduÖrnek
Şöyle yaparız.
template<typename T, typename F>
T lazy_value_or(const std::optional<T> &opt, F fn) {
if(opt) return opt.value();
return fn();
}
ÖrnekŞöyle yaparız.
template <typename F>
struct Lazy
{
F f;
operator decltype(f())() const
{
return f();
}
};
template <typename F>
Lazy(F f) -> Lazy<F>;
int main()
{
std::optional<int> o;
int i = o.value_or(Lazy{[]{return 0;}});
}
Diğer seçenekler
Eğer elimizde std::optional yoksa, ve boost::optional kullanmak istemiyorsak şöyle yapabiliriz.
1. unique_ptr kullanabiliriz.
Şöyle yaparız.
std::unique_ptr<double> possiblyFailingCalculation();
std::unique_ptr kendi içine null kontrolü yaptığı için kolaylıkla kullanılabilir.2. std::pair kullanılabilir.
Örnek
Şöyle yaparız.
std::pair<double,bool> possiblyFailingCalculation();
ÖrnekŞöyle yaparız.
using std_optional_int = std::optional<int>;
using my_optional_int = std::pair<int, bool>;
3. Eski usul kodlarız.
Yani şöyle kodlayacağımıza
std::optional<double> possiblyFailingCalculation()
Şöyle yaparız.
bool possiblyFailingCalculation(double& output);
Hiç yorum yok:
Yorum Gönder