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)); // 成功
}

猜你喜欢

转载自blog.csdn.net/sunlin972913894/article/details/102983033