[2.7] variant变体

3.1 std::variant

代码:https://github.com/leoda1/the-notes-of-cuda-programming/tree/main/code/CPU

0. 前言

std::variant是C++17引入的标准库类型,表示多个可能类型中的一个。类似于联合体(union),但是更安全易于使用。

union分配的内存只管最大的成员,union的所有成员share同一个内存空间。这就导致如下安全问题:

#include <iostream>

union MyUnion {
    int intValue;
    double doubleValue;
};

int main() {
    MyUnion myUnion;

    myUnion.doubleValue = 3.14;

    std::cout << "Integer Value: " << myUnion.intValue << "\n";

    return 0;
}
/*
Integer Value: 1374389535
*/

这里的int变量是未定义类型但是输出了莫名其妙的东西,所以c++17出现的variant就是为了解决这个潜在的问题。

1. variant是什么

std::variant 是对传统 union 的改进,因为它确保了类型安全,并为处理不同类型的值提供了一种方便的方法。

// Variant_exp1.cpp
#include <iostream>
#include <variant>

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

    myVariant = 42; /* Store an int */

    std::cout << std::get<double>(myVariant) << std::endl;

    return 0;
}

// g++ -std=c++17 demo.cpp -o demo
/*
terminate called after throwing an instance of 'std::bad_variant_access'
  what():  Unexpected index
Aborted (core dumped)
*/

这里创建的是包含intdoublevariant变量,但是只给int赋值了,在用get访问variantdouble变量就报错了。

再来看一个范例

// Variant_exp2.cpp
#include <iostream>
#include <variant>
#include <string>

using namespace std;

int main() {
    variant<int, string> myIntStr;
    myIntStr = 100;
    myIntStr = "leoda";

    try {
        if (holds_alternative<int>(myIntStr)) {
            cout << "value as int is : " << get<int>(myIntStr) << endl;
        } else if (holds_alternative<string>(myIntStr)) {
            cout << "value as string is : " << get<string>(myIntStr) << endl;
        } else {
            cout << "error"<< endl;
        }
    } catch (bad_variant_access& e){
        cerr << "Error: " << e.what() << endl;
    }
    return 0;
}
// g++ -std=c++17 Variant_exp2.cpp -o Variant_exp2
/******************************************************************
value as string is : leoda
*******************************************************************/

2. variant的公共成员函数

默认构造函数:

std::variant<int, double, std::string> myVariant; /* Default construction */

赋值构造函数:

std::variant<int, double> myVariant;
myVariant = 42; /* Assigns an int */

index()方法返回当前类型的索引:

std::variant<int, float, std::string> var;
var = 42;
std::cout << "Current index: " << var.index() << std::endl;  // 输出 0
var = 3.14f;
std::cout << "Current index: " << var.index() << std::endl;  // 输出 1

std::variant_alternative 获取类型

用来获取 std::variant 模板参数列表中指定索引处的类型。

std::variant<int, float, std::string> var;

// 获取索引 0 对应的类型
using T0 = std::variant_alternative<0, decltype(var)>::type;
std::cout << "Type at index 0: " << typeid(T0).name() << std::endl;  // 输出 int

// 获取索引 1 对应的类型
using T1 = std::variant_alternative<1, decltype(var)>::type;
std::cout << "Type at index 1: " << typeid(T1).name() << std::endl;  // 输出 float

valueless_by_exception() 查看variant变量是否赋值了

std::variant<int, double> myVariant;
if (myVariant.valueless_by_exception()) {
    /* Handle the case where the variant has no value */
}

综合范例:

/******************************************************************
 * Author      : Da Liu
 * Date        : 2025-03-09
 * File Name   : Variant_exp3.cpp
 * Description : variant的部分成员函数的使用
 *****************************************************************/

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

int main() {
    std::variant<int, float, std::string> var = "Hello";

    std::cout << "Current index: " << var.index() << std::endl;  // 输出 2

    if (var.index() == 0) {
        using T = std::variant_alternative<0, decltype(var)>::type;
        std::cout << "Current type: " << typeid(T).name() << " with value " << std::get<T>(var) << std::endl;
    } else if (var.index() == 1) {
        using T = std::variant_alternative<1, decltype(var)>::type;
        std::cout << "Current type: " << typeid(T).name() << " with value " << std::get<T>(var) << std::endl;
    } else if (var.index() == 2) {
        using T = std::variant_alternative<2, decltype(var)>::type;
        std::cout << "Current type: " << typeid(T).name() << " with value " << std::get<T>(var) << std::endl;
    }

    return 0;
}
// g++ -std=c++17 Variant_exp3.cpp -o Variant_exp3
/*********************************************************************************************
Current index: 2
Current type: NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE with value Hello
**********************************************************************************************/

Swap:(需要类型一致)

std::variant<int, double> var1 = 42;
std::variant<int, double> var2 = 3.14;
std::swap(var1, var2);

empalce():提供的参数进行就地构造

std::variant<int, std::string> myVariant;
myVariant.emplace<std::string>("Hello");

visit()

用于访问 std::variant 中存储的值。它通过接受一个访问者(visitor)对象来对 std::variant 中当前存储的值进行操作。访问者对象可以是一个函数对象、lambda 表达式或具有重载 operator() 的结构体。基本用法包括:

  • 定义一个 std::variant 对象,包含多个可能的类型。
  • 创建一个访问者对象,定义对每种可能类型的操作。
  • 使用 std::visit 传递访问者对象和 std::variant 对象。

范例:

//basic
#include <variant>
#include <iostream>
#include <string>

int main() {
    std::variant<int, float, std::string> var = "Hello, World!";

    auto visitor = [](auto&& arg) {
        std::cout << "Value: " << arg << std::endl;
    };

    std::visit(visitor, var);  // 输出: Value: Hello, World!

    var = 42;
    std::visit(visitor, var);  // 输出: Value: 42

    var = 3.14f;
    std::visit(visitor, var);  // 输出: Value: 3.14

    return 0;
}

// 结构体作为访问者
#include <variant>
#include <iostream>
#include <string>

struct Visitor {
    void operator()(int i) const {
        std::cout << "Integer: " << i << std::endl;
    }

    void operator()(float f) const {
        std::cout << "Float: " << f << std::endl;
    }

    void operator()(const std::string& s) const {
        std::cout << "String: " << s << std::endl;
    }
};

int main() {
    std::variant<int, float, std::string> var;

    var = 42;
    std::visit(Visitor{}, var);  // 输出: Integer: 42

    var = 3.14f;
    std::visit(Visitor{}, var);  // 输出: Float: 3.14

    var = "Hello, World!";
    std::visit(Visitor{}, var);  // 输出: String: Hello, World!

    return 0;
}

// 访问多个变体
#include <variant>
#include <iostream>
#include <string>

struct Visitor {
    void operator()(int i, float f) const {
        std::cout << "Integer: " << i << ", Float: " << f << std::endl;
    }

    void operator()(int i, const std::string& s) const {
        std::cout << "Integer: " << i << ", String: " << s << std::endl;
    }

    void operator()(float f, const std::string& s) const {
        std::cout << "Float: " << f << ", String: " << s << std::endl;
    }

    void operator()(const auto& a, const auto& b) const {
        std::cout << "Other types: " << a << ", " << b << std::endl;
    }
};

int main() {
    std::variant<int, float, std::string> var1 = 42;
    std::variant<int, float, std::string> var2 = "Hello, World!";

    std::visit(Visitor{}, var1, var2);  // 输出: Integer: 42, String: Hello, World!

    var2 = 3.14f;
    std::visit(Visitor{}, var1, var2);  // 输出: Integer: 42, Float: 3.14

    return 0;
}

3 总结

std::variant<T, U, ...>代表一个多类型的容器,容器中的值是制定类型的一种,是通用的 Sum Type,对应 Rust 的enum。是一种类型安全的union,所以也叫做tagged union。与union相比有两点优势:

  1. 可以存储复杂类型,而 union 只能直接存储基础的 POD 类型,对于如std::vectorstd::string就等复杂类型则需要用户手动管理内存。
  2. 类型安全,variant 存储了内部的类型信息,所以可以进行安全的类型转换,c++17 之前往往通过union+enum来实现相同功能。

通过使用std::variant<T, Err>,用户可以实现类似 Rust 的std::result,即在函数执行成功时返回结果,在失败时返回错误信息,上文的例子则可以改成:

std::variant<ReturnType, Err> func(const string& in) {
    ReturnType ret;
    if (in.size() == 0)
        return Err{"input is empty"};
    // ...
    return {ret};
}

1

### 语义分割在遥感图像中的应用及技术介绍 #### 什么是语义分割语义分割是一种计算机视觉任务,旨在对输入图像的每个像素分配一个标签,从而实现像素级分类。这种技术可以用于识别和区分图像中的不同对象或区域[^1]。 #### 遥感图像中的语义分割 遥感图像通常具有高分辨率、大范围覆盖的特点,因此对其进行精确的语义分割是一项挑战性的任务。通过深度学习模型,特别是卷积神经网络(CNN)及其变体(如 U-Net 和 Transformer),可以在遥感图像中实现高效的语义分割。这些方法能够自动提取特征并完成复杂的模式匹配,使得遥感图像中的地物类别得以精准标注[^2]。 #### 应用场景 语义分割在遥感领域的典型应用场景包括但不限于以下几个方面: - **城市规划**:通过对建筑群、道路网等结构进行精细划分,支持城市的合理布局和发展决策。 - **环境监测**:利用语义分割检测森林覆盖率变化、水体污染扩散情况以及土地退化程度。 - **农业评估**:帮助农民监控作物生长状态,预测产量,并优化灌溉策略。 具体而言,“Semantic Segmentation of Remote Sensing Images”这一开源项目展示了如何借助先进的深度学习框架处理遥感数据集,提供了一套完整的解决方案来应对上述需求[^3]。 #### 技术实现方式 目前主流的技术路线主要依赖于类似于U-Net架构或者融合了注意力机制的Transformers。前者凭借其编码器解码器的设计思路,在保持空间信息的同时增强了上下文关联能力;后者则进一步提升了全局感知力,尤其适合复杂背景下的目标定位与辨识工作[^4]。 以下是基于Python的一个简单示例代码片段展示如何加载预训练权重文件来进行测试推理: ```python import torch from torchvision import models def load_model(model_path, device='cpu'): model = models.segmentation.deeplabv3_resnet101(pretrained=False) checkpoint = torch.load(model_path, map_location=device) model.load_state_dict(checkpoint['model']) return model.to(device) device = 'cuda' if torch.cuda.is_available() else 'cpu' pretrained_weights = './semantic_segmentation.pth' segmentation_model = load_model(pretrained_weights, device) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小马敲马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值