最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++17中的std::optional的具體使用

 更新時間:2021年01月13日 11:23:55   作者:hzSomthing  
這篇文章主要介紹了C++17中的std::optional的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

直入主題

本篇之中,僅僅述及 std::optional ,其它和 variant 相關(guān)的話題以后再說吧。

std::optional 也劃入 variant 類別中,其實(shí)它還是談不上可稱為變體類型的,但新版本中的三大件(optional,any and variant)也可以歸一類無妨。

C++17 之前

在 C 時代以及早期 C++ 時代,語法層面支持的 nullable 類型可以采用指針方式: T* ,如果指針為 NULL (C++11 之后則使用 nullptr ) 就表示無值狀態(tài)(empty value)。

typedef template <typename T> T* NullableT;
NullableT<int> pInt = nullptr;

為了更好地使用這個類別而不是總是采用指針,需要對其進(jìn)行封裝。下面給出一個示例(但并未完善):

// 使用 C++11 語法
namespace cmdr {
 template<typename T>
 class Nullable {
 public:
  Nullable() = default;

  virtual ~Nullable(){ if (_value) delete _value; }

 public:
  Nullable(const Nullable &o) { _copy(o); }

  Nullable &operator=(const Nullable &o) {
   _copy(o);
   return *this;
  }

  Nullable &operator=(const T &o) {
   this->_value = o;
   return *this;
  }

 private:
  void _copy(const Nullable &o) {
   this->_value = o._value;
  }

 public:
  T &val() { return *_value; }

  const T &val() const { return *_value; }

  void val(T &&v) {
   if (!_value)
    _value = new T;
   (*_value) = v;
  }

  explicit operator T() const { return val(); }

  explicit operator T() { return val(); }

  // operator ->
  // operator *
  
  [[nodiscard]] bool is_null() const { return !_value; }
  
 private:
  T *_value{nullptr};
 };// class Nullable<T>
}

所以,這個 Nullable<T> 現(xiàn)在很像 C# 或者 Kotlin 中的 T?。使用它和直接使用 T 差不多,只是隱含著 new/delete 的額外開銷,當(dāng)然我們也可以采用別的實(shí)現(xiàn)方案例如增加一個額外的 bool 成員變量來表示是否尚未賦值,這樣就可以去掉 heap allocating 開銷,孰優(yōu)孰劣也未必可以計(jì)較。

std::optional in C++17

std::optional 類似于 Nullable<T> 和 std::variant 的聯(lián)合體,它管理一個 Nullable 變體類型。

但它和 Nullable<T> 不同之處在于,optional 實(shí)現(xiàn)的更為精煉和全面:Nullable 是剛才我手寫的,甚至沒經(jīng)過編譯器檢驗(yàn),也缺乏大多數(shù)重載以及構(gòu)造特性。optional 在構(gòu)造對象的開銷方面比 Nullable 好無數(shù)倍,因?yàn)樗軌蚶迷粯?gòu)造特性使得自身的開銷趨向于 0 而只需要 T 對象的構(gòu)造開銷,而 Nullable 為了表達(dá)出早期(C++03)的狀態(tài)直接采用了 new/delete 來簡化代碼。

如果想要改進(jìn)前文中 Nullable<T> 的實(shí)現(xiàn),使其和 optional 一樣地完善,則需要關(guān)注如下幾點(diǎn):

  • 去掉 new / delete 機(jī)制,考慮采用一個空結(jié)構(gòu)來表達(dá)尚未賦值的狀態(tài):事實(shí)上,optional 使用了 std::nullopt_t 來表述該狀態(tài)。
  • 完善操作符重載
  • 加入 swap 特性支持
  • 加入原位構(gòu)造特性支持

optional 和 variant 也不同,variant 是提前確定好一組可選的類型,你只能在這一組類型中進(jìn)行變換,而 optional 是具體化到一個特定類型的,你不能動態(tài)地將不同類型的值賦予 optional 的變量。

optional 從語法意義上來說,就是一個完美版的 Nullable<T> ,你可以將其和 Kotlin 的可空類型等價。

使用

我們可以以多種方式來構(gòu)造、聲明 optional 的變量,最原始的方式是在構(gòu)造參數(shù)時傳入值對象:

std::optional<int> opt_int(72);
std::optional opt_int2(8);
std::optional opt_int2(std::string("a string"));

使用 std::make_optional<T> 是比較 meaningful 的一種,而且也是更整潔的原位構(gòu)造:

auto opt_double = std::make_optional(3.14);
auto opt_complex = std::make_optional<std::complex<double>>(3.0, 4.0);
std::optional<std::complex<double>> opt_complex2{std::in_place, 3.0, 4.0};

使用原位構(gòu)造

// constructing a string in-place
std::optional<std::string> o1(std::in_place, "a string");
// with a repeated spaces
std::optional<std::string> o1(std::in_place, 8, ' ');

has_value 可以用于測試有沒有值,是否尚未賦值:

auto x = std::make_optional(9);
std::optional<int> y;
assert(x.hash_value() == true);
assert(y.hash_value() == false);

std::cout << x.value();
std::cout << y.value_or(0);

value() 和 value_or() 是抽出 T 值的方法,含義明顯,不必贅述。當(dāng)無值或者類型不能轉(zhuǎn)換時,value() 有可能拋出異常 std::bad_optional_access,如果想要避免則可以使用 value_or。

對于復(fù)合對象來說,原位構(gòu)造方式賦值 emplace 也是可用的。同樣地也可以善加利用 swap。

應(yīng)用

optional 相當(dāng)于一個全類型的 Nullable 類型,所以在運(yùn)用工廠模式時將其作為創(chuàng)建器的返回值將會是非常適合的選擇,好過無包裝的 T* 或者智能指針。因?yàn)楫?dāng)你使用智能指針的工廠模式時,創(chuàng)建器只能創(chuàng)建基于一個公共基類的實(shí)例,所以受制較多。但采用 optional 時則不會收到基類指針的限制。

下面是來自于 cppreference 的示例: 

#include <string>
#include <functional>
#include <iostream>
#include <optional>
 
// optional 可用作可能失敗的工廠的返回類型
std::optional<std::string> create(bool b) {
 if(b)
  return "Godzilla";
 else
  return {};
}
 
// 能用 std::nullopt 創(chuàng)建任何(空的) std::optional
auto create2(bool b) {
 return b ? std::optional<std::string>{"Godzilla"} : std::nullopt;
}
 
// std::reference_wrapper 可用于返回引用
auto create_ref(bool b) {
 static std::string value = "Godzilla";
 return b ? std::optional<std::reference_wrapper<std::string>>{value}
    : std::nullopt;
}
 
int main()
{
 std::cout << "create(false) returned "
    << create(false).value_or("empty") << '\n';
 
 // 返回 optional 的工廠函數(shù)可用作 while 和 if 的條件
 if (auto str = create2(true)) {
  std::cout << "create2(true) returned " << *str << '\n';
 }
 
 if (auto str = create_ref(true)) {
  // 用 get() 訪問 reference_wrapper 的值
  std::cout << "create_ref(true) returned " << str->get() << '\n';
  str->get() = "Mothra";
  std::cout << "modifying it changed it to " << str->get() << '\n';
 }
}

// Output
create(false) returned empty
create2(true) returned Godzilla
create_ref(true) returned Godzilla
modifying it changed it to Mothra

此外,在搜索算法中返回搜索結(jié)果或者返回沒找到狀態(tài),可以不必使用 bool 加上 search::result 了,可以直接返回 std::optional<search::result>。

這樣的設(shè)計(jì)策略完全可以產(chǎn)生深遠(yuǎn)的影響。從有潔癖的我的心態(tài)出發(fā),大多數(shù)類庫都可以據(jù)此重新改寫,從而得到更簡練、更 meaningful 的接口。而更富有表達(dá)力的接口反過來也能影響到算法的實(shí)現(xiàn)部分,它們將會變得更易讀,更可維護(hù)。

那些 Machine Learning 算法,寫出來如同天書一般,但借助新的手段重構(gòu)的話,有望可以增進(jìn)理解程度。

所以,像 C# 具有了 Nullable 類型幾十年(稍稍有點(diǎn)夸張)了之后,C++17 才正式支持 std::optional 實(shí)在是相當(dāng)操蛋的一件事情。

和 Kotlin 比較Permalink

和 Kotlin 相比較的話,現(xiàn)階段的 optional 不但冗長,而且缺乏一大組閉包工具(let,apply,類型診斷,空安全)。多數(shù)人將這些工具稱作語法糖,但我更希望它們被視為必需品。下面是一段 Kotlin 的代碼塊,可以看出整體上它們的簡練性,而 std::optional 嘛,實(shí)際上還差得遠(yuǎn),看起來也不可能趕得上了:

if (obj is String!!) { // 對于 String? obj 也一樣生效,自動升級為非空版本
 print(obj.length)
}

if (obj !is String) { // 與 !(obj is String) 相同
 print("Not a String")
} else {
 print(obj.length)
}

fun demo(x: Any) {
 if (x is String) {
  print(x.length) // x 自動轉(zhuǎn)換為字符串
 }
}

when (x) {
 is Int -> print(x + 1)
 is String -> print(x.length + 1)
 is IntArray -> print(x.sum())
}

// 可空類型的集合
val nullableList: List<Int?> = listOf(1, 2, null, 4)
val intList: List<Int> = nullableList.filterNotNull()

// 可空類型的簡化診斷代碼塊
Int? zz = 8;
zz?.let {
 sum += it // 僅當(dāng) zz 非空時, 塊內(nèi)才被執(zhí)行,it 表示 zz 的非空版
}

Kotlin 的這套語法機(jī)制真的是讓人如同吃了人參果,無一個毛孔不舒服。但是它的實(shí)現(xiàn)機(jī)制是低代價而非無代價的,從這一點(diǎn)上來說,C++ 將不可能采納等效的新語法,只能使用 std::optional<T> 這樣的老奶奶裹腳布方案了。但它至少比沒有的好。

小結(jié)

通過和 Kotlin 的比較,我們不無悲哀地看到,比較于 C++11 甚至于 C++98,optional 固然是個提升,然而受制于 C++ 標(biāo)準(zhǔn)委員會以及歷史包袱的原因,簡練有效的表達(dá)方式在現(xiàn)在不可能,在未來的 C++2x, 3x 中也應(yīng)該是行不通的。

參考鏈接

std::optional at cppreference

到此這篇關(guān)于C++17中的std::optional的具體使用的文章就介紹到這了,更多相關(guān)C++17 std::optional內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 實(shí)例講解C++編程中對設(shè)計(jì)模式中的原型模式的使用

    實(shí)例講解C++編程中對設(shè)計(jì)模式中的原型模式的使用

    這篇文章主要介紹了C++編程中對設(shè)計(jì)模式中的原型模式的使用實(shí)例,包括原型模式中對C++的深拷貝和淺拷貝的處理,需要的朋友可以參考下
    2016-03-03
  • C++項(xiàng)目實(shí)戰(zhàn)之makefile使用

    C++項(xiàng)目實(shí)戰(zhàn)之makefile使用

    這篇文章主要介紹了C++項(xiàng)目實(shí)戰(zhàn)之makefile使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 深入解析C++中多態(tài)性和虛函數(shù)使用原理

    深入解析C++中多態(tài)性和虛函數(shù)使用原理

    這篇文章主要為大家介紹了深入解析C++中多態(tài)性和虛函數(shù)使用原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • CrashRpt使用案例詳解

    CrashRpt使用案例詳解

    這篇文章主要介紹了CrashRpt使用案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • c語言中缺省參數(shù)的類型總結(jié)

    c語言中缺省參數(shù)的類型總結(jié)

    在本篇文章里小編給大家整理了一篇關(guān)于c語言中缺省參數(shù)的類型總結(jié)內(nèi)容,有興趣的朋友們可以跟著學(xué)習(xí)參考下。
    2021-09-09
  • OpenCV?直方圖均衡化的實(shí)現(xiàn)原理解析

    OpenCV?直方圖均衡化的實(shí)現(xiàn)原理解析

    直方圖均衡化是通過拉伸像素強(qiáng)度分布范圍來增強(qiáng)圖像對比度的一種方法,今天通過本文給大家介紹OpenCV?直方圖均衡化的實(shí)現(xiàn)原理解析,感興趣的朋友跟隨小編一起看看吧
    2022-01-01
  • C++全面精通類與對象

    C++全面精通類與對象

    類和對象是兩種以計(jì)算機(jī)為載體的計(jì)算機(jī)語言的合稱。對象是對客觀事物的抽象,類是對對象的抽象。類是一種抽象的數(shù)據(jù)類型;變量就是可以變化的量,存儲在內(nèi)存中—個可以擁有在某個范圍內(nèi)的可變存儲區(qū)域
    2022-05-05
  • 可能是全網(wǎng)最詳細(xì)的Qt連接MySQL數(shù)據(jù)庫教程

    可能是全網(wǎng)最詳細(xì)的Qt連接MySQL數(shù)據(jù)庫教程

    QT眾所周知是一個開源的,以C++為底層的可視化工具庫,下面這篇文章主要給大家介紹了關(guān)于最詳細(xì)的Qt連接MySQL數(shù)據(jù)庫教程的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • C語言 自增自減運(yùn)算的區(qū)別詳解及實(shí)例

    C語言 自增自減運(yùn)算的區(qū)別詳解及實(shí)例

    這篇文章主要介紹了C語言中的++a和a++的區(qū)別詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • C++簡易版Tensor實(shí)現(xiàn)方法詳解

    C++簡易版Tensor實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了C++簡易版Tensor的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值
    2022-08-08

最新評論

九龙城区| 通道| 贵州省| 思南县| 吴旗县| 新密市| 屯昌县| 衡阳市| 徐水县| 和平区| 余干县| 固原市| 凌海市| 邛崃市| 石泉县| 茶陵县| 沙坪坝区| 沾益县| 阳高县| 徐州市| 阿拉尔市| 开封县| 潜山县| 平山县| 泾源县| 思南县| 资兴市| 志丹县| 来凤县| 承德县| 凤冈县| 四会市| 邹城市| 鹤壁市| 海原县| 玉林市| 苗栗县| 昌平区| 许昌市| 安多县| 连南|