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
元素的引用。
複雜度:常數。
元組式訪問指定的元素 (函數模板) |
|
(C++11) |
訪問 pair 的一個元素(函數模板) |
(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)); // 成功
}