C++ get(), at()和variant類型

1、std::get(std::span)

template< std::size_t I, class T, std::size_t N >
constexpr T& get( std::span<T,N> s ) noexcept;

獲得到 span s 的第 I 個元素的引用。

該 span 必須擁有靜態長度(即 N != std::dynamic_extent )且 I 必須是範圍 [0, N) 中的整數值。這在編譯時強制,與 operator[] 相反。

參數  s :要提取內容的 span

返回值:到 s 的第 I 元素的引用。

複雜度:常數。

std::get(std::tuple)

元組式訪問指定的元素
(函數模板)

std::get(std::pair)

(C++11)

訪問 pair 的一個元素
(函數模板)

std::get(std::variant)

(C++17)

以給定索引或類型(若類型唯一)讀取 variant 的值,錯誤時拋出異常
std::get(std::array) 訪問 array 的一個元素
.........  

事例:

#include <iostream>
#include <string>
#include <tuple>
#include <utility>
#include <array>
#include <variant>

int main()
{
    auto t = std::make_tuple(1, "Foo", 3.14);
    // 基於下標的訪問
    std::cout << "(" << std::get<0>(t) << ", " << std::get<1>(t)
              << ", " << std::get<2>(t) << ")\n";
    // 基於類型的訪問( C++14 起)
    std::cout << "(" << std::get<int>(t) << ", " << std::get<const char*>(t)
              << ", " << std::get<double>(t) << ")\n";
    // 注意: std::tie 和結構化綁定亦可用於分解 tuple

    auto p = std::make_pair(1, 3.14);
    std::cout << '(' << std::get<0>(p) << ", " << std::get<1>(p) << ")\n";
    std::cout << '(' << std::get<int>(p) << ", " << std::get<double>(p) << ")\n";

    std::array<int, 3> arr;
 
    // 設置值:
    std::get<0>(arr) = 1;
    std::get<1>(arr) = 2;
    std::get<2>(arr) = 3;
 
    // 獲取值:
    std::cout << "(" << std::get<0>(arr) << ", " << std::get<1>(arr)
              << ", " << std::get<2>(arr) << ")\n";

    std::variant<int, float> v{12}, w;
    int i = std::get<int>(v);
    w = std::get<int>(v);
    w = std::get<0>(v); // 效果同前一行
 
    //  std::get<double>(v); // 錯誤: [int, float] 中無 double
    //  std::get<3>(v);      // 錯誤:合法的 index 值是 0 和 1
 
    try {
      std::get<float>(w); // w 含有 int ,非 float :將拋出異常
    }
    catch (std::bad_variant_access&) {} //錯誤時拋 std::bad_variant_access異常

    return 0;
}
輸出:
(1, Foo, 3.14)
(1, Foo, 3.14)

(1, 3.14)
(1, 3.14)

(1, 2, 3)

2、at()

std::array<T,N>::at

reference at( size_type pos );

  (C++17 前)

constexpr reference at( size_type pos );

  (C++17 起)

const_reference at( size_type pos ) const;

  (C++14 前)

constexpr const_reference at( size_type pos ) const;

  (C++14 起)

返回位於指定位置 pos 的元素的引用,有邊界檢查。

參數:pos 要返回的元素的位置

返回值:到所需元素的引用。

異常:若 !(pos < size())  即 pos 不在容器範圍內,則拋出 std::out_of_range 類型的異常。

        C++容器類型重載了operator[]符,at()方法和operator[]的作用是一樣的,差別在於引入的at()方法比operator[]取元素要安全,C++標準不要求operator[]進行下標越界檢查,原因是爲了效率,總是強制下標越界檢查會增加程序的性能開銷。提供at()方法正是爲了彌補越界訪問檢查這一特性,用operator[]取元素髮生越界訪問導致程序奔潰,有可能直接報段錯誤,很難查找到問題代碼,而at()獲取元素超出範圍會拋出異常,容易捕捉到,總之,operator[]方法訪問元素效率高,at()訪問元素安全。

 

3、std::variant

類模板 std::variant 表示一個類型安全的聯合體std::variant 的一個實例在任意時刻要麼保有其一個可選類型之一的值,要麼在錯誤情況下無值(此狀態難以達成,見 valueless_by_exception )。

與聯合體在聚合初始化中的行爲一致, 若 variant 保有某個對象類型 T 的值,則直接於 variant 的對象表示中分配 T 的對象表示。不允許 variant 分配額外的(動態)內存。

variant 不容許保有引用、數組,或類型 void 。空 variant 亦爲病式(可用 std::variant<std::monostate> 代替)。

variant 容許保有同一類型多於一次,而且可保有同一類型的不同 cv 限定版本。

同聯合體,默認構造的 variant 保有其首個選項的值,除非該選項不是可默認構造的(該情況下 variant 亦非可默認構造:能用輔助類 std::monostate 使這種 variant 可默認構造)。

#include <variant>
#include <string>
#include <cassert>
 
int main()
{
    std::variant<int, float> v, w;
    v = 12; // v 含 int
    int i = std::get<int>(v);
    w = std::get<int>(v);
    w = std::get<0>(v); // 與前一行效果相同
    w = v; // 與前一行效果相同
 
//  std::get<double>(v); // 錯誤: [int, float] 中無 double
//  std::get<3>(v);      // 錯誤:合法下標值爲 0 與 1
 
    try {
      std::get<float>(w); // w 含 int 而非 float :將拋出
    }
    catch (const std::bad_variant_access&) {}
 
    using namespace std::literals;
 
    std::variant<std::string> x("abc"); // 轉換構造函數在無歧義時起作用
    x = "def"; // 轉換賦值在無歧義時亦起作用
 
    std::variant<std::string, void const*> y("abc");
    // 傳遞 char const * 時轉換成 void const *
    assert(std::holds_alternative<void const*>(y)); // 成功
    y = "xyz"s;
    assert(std::holds_alternative<std::string>(y)); // 成功
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章