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

C++訪問std::variant類型數(shù)據(jù)的幾種方式小結(jié)

 更新時間:2024年02月20日 15:06:14   作者:AlbertS  
std::variant是?C++17中引入的一個新的類模板,提供了一種存儲不同類型的值的方式,本文主要介紹了C++訪問std::variant類型數(shù)據(jù)的幾種方式小結(jié),具有一定的參考價值,感興趣的可以了解一下

前言

std::variant(可變體) 是 C++17 中引入的一個新的類模板,提供了一種存儲不同類型的值的方式,類似于之前版本中的 union(聯(lián)合體),但可以存儲非 POD 類型和類對象,能夠在運行時進行類型檢查和轉(zhuǎn)換,但具有更多的功能和更高的類型安全性,今天來看一下存儲在std::variant中的數(shù)據(jù)要怎么讀取。

variant的簡單使用

可以參考cppreference網(wǎng)站的使用示例,也可以看看下面這個例子:

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

int main()
{
    std::variant<int, double, std::string> value;

    value = 110;
    std::cout << "The value is an integer: " << std::get<int>(value) << std::endl;

    value = 0.618;
    std::cout << "The value is a double: " << std::get<double>(value) << std::endl;

    value = "hello world";
    std::cout << "The value is a string: " << std::get<std::string>(value) << std::endl;

    // value = true;        // Compilation error: cannot convert type bool to any of the alternative types
    // std::get<int>(value) // std::bad_variant_access exception: value holds a different type

    return 0;
}

在示例程序中,定義了一個 std::variant 對象 value 來存儲整型、浮點型和字符串類型中的任意一種,然后分別將 value 賦值為整型、浮點型和字符串類型,并使用 std::get 來獲取對應的值,此時可以正常打印 value 對象中存儲的值

當我們試圖將 value 賦值為其它未在定義變量時指定的類型時,編譯器將會報編譯錯誤,而當我我們試圖獲取 value 中不存在的類型的值時,程序?qū)伋?std::bad_variant_access 異常,可以使用 try-catch 已經(jīng)捕獲。

通過這段代碼我們可以得知,使用std::variant可以方便地存儲多種類型的數(shù)據(jù),并且能夠在運行時進行類型檢查和轉(zhuǎn)換,這使得代碼更加清晰易讀,便于維護。

variant相關函數(shù)和類

  • 成員函數(shù)
    • index:返回 variant 中保存用類型的索引下標
    • valueless_by_exception:返回 variant 是否處于因異常導致的無值狀態(tài)
    • emplace:原位構(gòu)造 variant 中的值
  • 非成員函數(shù)
    • visit:通過調(diào)用variant保存類型值所提供的函數(shù)對象獲取具體值
    • holds_alternative:檢查某個 variant 是否當前持有某個給定類型
    • std::get:以給定索引或類型讀取 variant 的值,錯誤時拋出異常
    • get_if:以給定索引或類型,獲得指向被指向的 variant 的值的指針,錯誤時返回空指針
  • 輔助類
    • monostate:用作非可默認構(gòu)造類型的 variant 的首個可選項的占位符類型(預防一些類型不提供無參構(gòu)造函數(shù))
    • bad_variant_access:非法地訪問 variant 的值時拋出的異常
    • variant_npos:非法狀態(tài)的 variant 的下標

訪問std::variant數(shù)據(jù)

從前面提到的例子和函數(shù)說明,我們可以看到有多種方式來訪問std::variant數(shù)據(jù),接一下來一起總結(jié)一下:

std::get搭配index函數(shù)使用

#include <iostream>
#include <variant>

int main()
{
    std::variant<double, int> value = 119;

    if (1 == value.index())
        std::cout << "The value is: " << std::get<1>(value) << std::endl;

    return 0;
}

先用 index() 查詢 variant保存的類型索引,然后在通過 std::get<NUMBER>() 獲取其中的值

std::get搭配std::holds_alternative函數(shù)使用

#include <iostream>
#include <variant>

int main()
{
    std::variant<double, int> value = 119;

    if (std::holds_alternative<int>(value))
        std::cout << "The value is: " << std::get<int>(value) << std::endl;

    return 0;
}

先通過 std::holds_alternative() 查詢 variant保存的類型,然后在通過 std::get<TYPE>() 獲取其中的值

std::get_if函數(shù)

#include <iostream>
#include <variant>

int main()
{
    std::variant<double, int> value = 119;

    if (auto p = std::get_if<int>(&value))
        std::cout << "The value is: " << *p << std::endl;

    return 0;
}

直接使用 std::get_if 函數(shù)獲取對應值的指針,如果類型不匹配會返回空指針

std::visit函數(shù)

使用函數(shù)visit函數(shù)訪問時,有點像使用std::sort這類函數(shù),可以搭配自定義的結(jié)構(gòu)(排序)重寫operator(),讓其變成可以被調(diào)用的函數(shù)對象,也可以定義lambda自帶可執(zhí)行特性。

自定義訪問結(jié)構(gòu)的寫法

#include <iostream>
#include <variant>

int main()
{
    std::variant<double, int> value = 119;

    struct VisitPackage
    {
        auto operator()(const double& v) { std::cout << "The value is: " << v << std::endl; }
        auto operator()(const int& v) { std::cout << "The value is: " << v << std::endl; }
    };

    std::visit(VisitPackage(), value);

    return 0;
}

定義lambda函數(shù)組重載

#include <iostream>
#include <variant>

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

int main()
{
    std::variant<double, int> value = 119;

    std::visit(overloaded {
      [] (const double& v) { std::cout << "The value is: " << v << std::endl; },
      [] (const int& v) { std::cout << "The value is: " << v << std::endl; }
    }, value);

    return 0;
}

這種方式將多個lambda放到一起形成重載,進而達到了訪問variant數(shù)據(jù)的目的。

overloaded是什么

上文例子中的最后一個中使用到了 overloaded,這令人眼花繚亂的寫法著實很詭異,不過我們可以從頭來分析一下,最后兩個例子中等價的兩部分是

struct VisitPackage
{
    auto operator()(const double& v) { std::cout << "The value is: " << v << std::endl; }
    auto operator()(const int& v) { std::cout << "The value is: " << v << std::endl; }
};

VisitPackage()

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

overloaded {
    [] (const double& v) { std::cout << "The value is: " << v << std::endl; },
    [] (const int& v) { std::cout << "The value is: " << v << std::endl; }
}

要想理解它們?yōu)槭裁吹葍r,我們首先的得弄清楚lambda表達式是什么,在剖析lambda之前先來看看 std::visit 函數(shù)需要的參數(shù)是什么,分析std::visit的參數(shù),先看 struct VisitPackage 結(jié)構(gòu)更容易一些。

std::visit的第一個參數(shù)

通俗的來說std::visit的第一個參數(shù)需要的是一個可執(zhí)行的對象,如果對象能被執(zhí)行就需要實現(xiàn) operator() 這個操作符,看起來像函數(shù)一樣,這就是為什么在 struct VisitPackage 中定義了 operator(),并且定義了兩個形成了參數(shù)不同的靜態(tài)重載,作用就是為了在訪問 variant 對象時適配不同的類型,在訪問variant 對象時會選擇最匹配的 operator() 函數(shù),進而實現(xiàn)了訪問variant中不同類型值行為不同的目的。

那lambda表達式能實現(xiàn)這個目的嗎?我們接著往下看

lambda 是什么

自從 C++11 引入lambda之后,對它贊美的聲音不絕于耳,那lambda表達式究竟是怎樣實現(xiàn)的呢?真的就是一個普通的函數(shù)嗎?我們看一個小例子:

int main() {
  int x = 5, y = 6;

  auto func = [&](int n) {
    return x + n;
  };

  func(7);

  return 0;
}

這是一個使用lambda表達式簡單的例子,代碼中定義了一個int類型參數(shù)的返回值也是int的lambda函數(shù),作用就是將外部變量x與函數(shù)參數(shù)的和返回,我們使用 cppinsights.io 網(wǎng)站來將此段代碼展開

int main()
{
    int x = 5;
    int y = 6;

    class __lambda_4_15
    {
    public:
        inline /*constexpr */ int operator()(int n) const
        {
            return x + n;
        }

    private:
        int & x;

    public:
        __lambda_4_15(int & _x)
        : x{_x}
        {}
    };

    __lambda_4_15 func = __lambda_4_15{x};
    func.operator()(7);
    return 0;
}

可以發(fā)現(xiàn)我們雖然定義了一個lambda函數(shù),但是編譯器為它生成了一個類 __lambda_4_15,生成了 int& 類型的構(gòu)造函數(shù),并實現(xiàn)了 operator操作符,再調(diào)用lambda函數(shù)時先生成了 __lambda_4_15類的對象,再調(diào)用類的 operator()函數(shù) func.operator()(7);,看到這里是不是似曾相識,雖然還不是很明白,但是和struct VisitPackage的定義總是有種說不清道不明的血緣關系。

弄清楚了lambda函數(shù)的本質(zhì),現(xiàn)在要實現(xiàn)的是怎么把多個lambda函數(shù)合成一個對象,并且讓他們形成重載,因為lambda函數(shù)本質(zhì)上存在一個類,只需要定義一個子類,繼承多個lambda表達式就可以了,其實 overloaded 這個模板類就是為了實現(xiàn)這個目的。

overloaded剖析

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

一時間看起來很難理解,它來自 en.cppreference.com 中介紹 std::visit 訪問 std::variant 的例子,可以換行看得更清楚一點:

// helper type for the visitor #4
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
// explicit deduction guide (not needed as of C++20)
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;

template<class… Ts> struct overloaded : Ts… { using Ts::operator()…; };

這是一個類模板的聲明,模板的名字是overloaded

分步拆解來看:

template<class… Ts> struct overloaded

  • 表示類的模板參數(shù)為可變長的參數(shù)包 Ts
  • 假設 Ts 包含 T1, T2, … , TN,那么這一句聲明可以展開為:template<class T1, class T2, …, class TN> struct overloaded

struct overloaded : Ts…

  • 表示類的基類為參數(shù)包 Ts 內(nèi)所有的參數(shù)類型
  • 假設 Ts 包含 T1, T2, … , TN,那么這一句聲明可以展開為:struct overloaded : T1, T2, …, TN

{ using Ts::operator()…; };

  • 這是一個函數(shù)體內(nèi)的變長 using 聲明
  • 假設 Ts 包含 T1, T2, … , TN,那么這一句聲明可以展開為:{ using T1::operator(), T1::operator(), …, TN::operator(); }
  • 經(jīng)過這步聲明,overloaded 類的參數(shù)包 Ts 內(nèi)所有的參數(shù)作為基類的成員函數(shù)operator()均被 overloaded 類引入了自己的作用域

template<class… Ts> overloaded(Ts…) -> overloaded<Ts…>;

  • 這是一個自動推斷向?qū)дf明,用于幫助編譯器根據(jù) overloaded 構(gòu)造器參數(shù)的類型來推導 overloaded 的模板參數(shù)類型,C++17需要,C++20已不必寫
  • 它告訴編譯器,如果 overloaded 構(gòu)造器所有參數(shù)的類型的集合為Ts,那么 overloaded 的模板參數(shù)類型就是 Ts 所包含的所有類型
  • 如果表達式a1, a2, …, an的類型分別為T1, T2, …, TN,那么構(gòu)造器表達式overloaded x{a1, a2, …, an} 推導出,overloaded的類型就是 overloaded<T1, T2, …, TN>

經(jīng)過這些解釋,我們可以認為在最后一個例子中可能產(chǎn)生了類似這樣的代碼:

#include <iostream>
#include <variant>

class __lambda_12_7
{
public:
    inline /*constexpr */ void operator()(const double & v) const
    {
        std::operator<<(std::cout, "The value is: ").operator<<(v).operator<<(std::endl);
    }
};

class __lambda_13_7
{
public:
    inline /*constexpr */ void operator()(const int & v) const
    {
        std::operator<<(std::cout, "The value is: ").operator<<(v).operator<<(std::endl);
    }
};

template<>
struct overloaded<__lambda_12_7, __lambda_13_7> : public __lambda_12_7, public __lambda_13_7
{
    using __lambda_12_7::operator();
    // inline /*constexpr */ void ::operator()(const double & v) const;

    using __lambda_13_7::operator();
    // inline /*constexpr */ void ::operator()(const int & v) const;
};

int main()
{
    std::variant<double, int> value = std::variant<double, int>(119);

    std::visit(overloaded{__lambda_12_7(__lambda_12_7{}), __lambda_13_7(__lambda_13_7{})}, value);
    return 0;
}

總結(jié)

  • std::variant 可以存儲多個類型的值,并且它會自動處理類型轉(zhuǎn)換和內(nèi)存分配
  • std::variant 可以存儲非 POD 類型和類對象,能夠在運行時進行類型檢查和轉(zhuǎn)換,具有更高的類型安全性
  • 可以使用 std::visit 全局函數(shù)來訪問 std::variant 中存儲的值,該函數(shù)根據(jù)存儲的值的類型自動選擇調(diào)用哪個函數(shù)對象
  • 可以使用 std::holds_alternative 函數(shù)來檢查變量中是否存儲了特定的類型
  • 定義lambda函數(shù)時,編譯器會為其生成一個類

 到此這篇關于C++訪問std::variant類型數(shù)據(jù)的幾種方式小結(jié)的文章就介紹到這了,更多相關C++訪問std::variant內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • VC6實現(xiàn)激活后臺窗口最佳方法

    VC6實現(xiàn)激活后臺窗口最佳方法

    這篇文章主要介紹了VC6實現(xiàn)激活后臺窗口最佳方法,實例分析了VC操作后臺窗口的技巧,需要的朋友可以參考下
    2015-06-06
  • 如何把C++的源代碼改寫成C代碼的方法

    如何把C++的源代碼改寫成C代碼的方法

    這篇文章主要介紹了如何把C++的源代碼改寫成C代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • C++實現(xiàn)LeetCode(130.包圍區(qū)域)

    C++實現(xiàn)LeetCode(130.包圍區(qū)域)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(130.包圍區(qū)域),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 深入探討POJ 2312 Battle City 優(yōu)先隊列+BFS

    深入探討POJ 2312 Battle City 優(yōu)先隊列+BFS

    本篇文章是對優(yōu)先隊列+BFS進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • C++中new的用法及說明

    C++中new的用法及說明

    這篇文章主要介紹了C++中new的用法及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C++三體星戰(zhàn)小游戲源代碼

    C++三體星戰(zhàn)小游戲源代碼

    這篇文章主要給大家介紹了關于C++三體星戰(zhàn)小游戲的相關資料,文中給出了詳細完整的代碼示例,對大家的學習或者工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • 詳解C++ thread用法總結(jié)

    詳解C++ thread用法總結(jié)

    這篇文章主要介紹了詳解C++ thread用法總結(jié),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • c++實現(xiàn)加載so動態(tài)庫中的資源

    c++實現(xiàn)加載so動態(tài)庫中的資源

    下面小編就為大家?guī)硪黄猚++實現(xiàn)加載so動態(tài)庫中的資源。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • Matlab繪制酷炫坐標區(qū)域的方法詳解

    Matlab繪制酷炫坐標區(qū)域的方法詳解

    這篇文章主要為大家詳細介紹了如何利用Matlab編寫一個能讓坐標區(qū)域變得很炫酷的修飾函數(shù),文中的示例代碼講解詳細,感興趣的可以了解一下
    2022-05-05
  • C語言之浮點數(shù)的表示與儲存方式

    C語言之浮點數(shù)的表示與儲存方式

    這篇文章主要介紹了C語言之浮點數(shù)的表示與儲存方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03

最新評論

富川| 长顺县| 桓仁| 瑞昌市| 安宁市| 同德县| 湖州市| 宜城市| 安岳县| 镇原县| 鸡西市| 六枝特区| 宿迁市| 博爱县| 三明市| 莱阳市| 金门县| 射阳县| 红桥区| 台北县| 龙川县| 全椒县| 金湖县| 怀仁县| 尉犁县| 新化县| 柳河县| 防城港市| 雷州市| 延吉市| 军事| 双牌县| 仪征市| 兴仁县| 调兵山市| 河北省| 五大连池市| 定州市| 环江| 泉州市| 义马市|