首頁 > 軟體

C++17使用std::optional表示可能存在的值

2022-07-20 18:02:16

前言

平時寫程式碼會遇到一種傳遞引數特殊值標記特殊流程,或者函數返回值存在魔法數的情況,很需要一種標記引數或返回值狀態的結構,那麼在 C++17 標準下提供了 std::optional 這個模板類,可以表示一個值不存在的狀態,一起來看看用法吧。

返回一個bool值

以下例子純屬虛構,只為說明問題,無實際意義

bool getBoolVal(int a, int b)
{
    int* n = new int;
    if (!n)
        return false;

    *n = 1;

    if (a + *n > b)
        return true;
    else
        return false;
}

int main()
{
    if (getBoolVal(10, 9))
        std::cout << 1 << std::endl;
    else
        std::cout << 1 << std::endl;

    return 0;
}

這個例子中的函數 getBoolVal 本意是想返回一個 bool 型別的判斷結果,但是函數中有一些異常情況時,比如申請記憶體異常時,也會返回一個bool值,這是與原判斷結果語意不同的,所以需要單獨返回這種情況,如果也放到同一個返回值中會導致含義模糊,這時可以考慮使用參照變數引數來返回實際比較結果。

bool getBoolVal(int a, int b, bool& ret)
{
    int* n = new int;
    if (!n)
        return false;

    *n = 1;

    if (a + *n > b)
        ret = true;
    else
        ret = false;

    return true;
}

int main()
{
    bool ret = false;
    if (getBoolVal(10, 9, ret))
        std::cout << "error" << std::endl;
    else
    {
        if (ret)
            std::cout << 1 << std::endl;
        else
            std::cout << 0 << std::endl;
    }

    return 0;
}

這個參照引數 ret 使用起來有點不方便,那把兩個值都返回怎麼樣,雖然C++不允許有多個返回值,但可以把它們包裝成 std::pair 或者 std::tuple 來返回,再來改寫一下:

std::pair<bool, bool> getBoolVal3(int a, int b)
{
    int* n = new int;
    if (!n)
        return {false, false};

    *n = 1;

    if (a + *n > b)
        return {true, true};
    else
        return {true, false};
}

int main()
{
    auto [err, ret] = getBoolVal(10, 9);
    if (err)
        std::cout << "error" << std::endl;
    else
    {
        if (ret)
            std::cout << 1 << std::endl;
        else
            std::cout << 0 << std::endl;
    }

    return 0;
}

這種方法把實際的返回值,搭配一個表示狀態的 bool 變數,組成 std::pair 進行返回,基本上得到而來語意明確的目的,但是看起來還是不太優雅,而 std::optional 可以幫助我們實現類似的需求,並且程式碼看起來能更簡潔一點。

使用 std::optional 改寫

std::optional 本身是一個模板類:會有一個 std::nullopt

template <class T>
class optional;

它內部有兩種狀態,要麼有一個T型別的值,要麼用 std::nullopt 表示沒有值,檢視一個 std::optional 物件是否有值,可以用 has_value() 進行判斷,當一個 std::optional 有值時,可以通過用指標的方式(*號和->號)來使用它,或者用 value()函數取它的值,下面我們用它來改寫一下之前的實現:

std::optional<bool> getBoolVal4(int a, int b)
{
    int* n = new int;
    if (!n)
        return std::nullopt;

    *n = 1;

    if (a + *n > b)
        return true;
    else
        return false;
}


int main()
{
    std::optional<bool> ret = getBoolVal(10, 9);
    if (ret.has_value())
        std::cout << "error" << std::endl;
    else
    {
        if (ret.value())
            std::cout << 1 << std::endl;
        else
            std::cout << 0 << std::endl;
    }

    return 0;
}

使用了 std::optional 之後就把 bool 型別之前的兩態變成了三態,很多類似的邏輯也被封裝成了函數,使用它之後程式碼更清晰了,從此可以告別一些煩人的魔法數了,一些函數引數也可以使用 std::optional 來包裝,用法類似,在此就不展開說了。

總結

  • std::optional 是一個模板類,可以表示一個可能存在的值
  • std::optional 的內部有兩種狀態,要麼表示一個T型別的值,要麼用 std::nullopt 表示沒有值
  • 可以用 has_value() 判斷一個 std::optional 是否有值,然後用 value() 函數取它表示的值

到此這篇關於C++17使用std::optional表示可能存在的值的文章就介紹到這了,更多相關C++17 std::optional內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com