如何在 C++ 中高效地使用 std::variant 进行错误处理?

问题描述 投票:0回答:1

我最近开始探索在现代 C++(C++17 及更高版本)中使用

std::variant
来处理错误并同时从函数返回值,有点类似于 Rust 的
Result
类型。我了解
std::variant
的基本用法,但我正在寻找专为错误处理量身定制的高效且优雅的模式。

这是我迄今为止尝试过的:

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

using Result = std::variant<std::string, int>;

Result computeValue(int x) {
    if (x < 0) {
        return "Negative input error";
    }
    return x * 2;
}

void handleResult(const Result& result) {
    std::visit([](auto&& arg) {
        using T = std::decay_t<decltype(arg)>;
        if constexpr (std::is_same_v<T, std::string>) {
            std::cout << "Error: " << arg << std::endl;
        } else {
            std::cout << "Computed value: " << arg << std::endl;
        }
    }, result);
}

int main() {
    Result res1 = computeValue(10);
    Result res2 = computeValue(-1);
    handleResult(res1);
    handleResult(res2);
    return 0;
}

我目前正在寻找以下方面的反馈:

  1. 以这种方式使用
    std::variant
    时的效率考虑。
  2. 任何潜在的陷阱或可以对此模式进行的改进。
  3. 在性能和代码清晰度方面,这种方法与使用异常或其他传统错误处理方法相比如何?

在使用

std::variant
进行错误处理时,我将不胜感激任何见解或最佳实践示例。

c++ c++17
1个回答
0
投票

以这种方式使用

std::variant
时的效率考虑。

因为您必须在快乐路径上进行访问,所以在许多平台上,它的性能会低于使用异常,而在不抛出异常时,开销可能接近于零。

任何潜在的陷阱或可以对此模式进行的改进。

std::string
是相当常见的类型。如果您的字符串操作可能会失败,会发生什么?

您可能想创建一个特定的

Error
类型,即使它只是

struct Error {
    std::string what;
};

int
上的操作“提升”为
Result
类型也很好:

template <typename UnaryOperation>
Result transform(UnaryOperation op, Result input) -> Result {
    return std::visit([](auto&& arg) {
    using T = decltype(arg);
    if constexpr (std::is_same_v<std::decay_t<T>, Error>) {
        return std::forward<T>(arg);
    } else {
        return op(std::forward<T>(arg));
    }, input);
}

template <typename BinaryOperation>
Result transform(BinaryOperation op, Result lhs, Result rhs) -> Result {
    return std::visit([](auto&& left, auto&& right) {
    using L = decltype(left);
    using R = decltype(right);
    if constexpr (std::is_same_v<std::decay_t<L>, Error> && std::is_same_v<std::decay_t<R>, Error>) {
        return Error{ std::forward<L>(left).what + std::forward<R>(right).what };
    } else if constexpr (std::is_same_v<std::decay_t<L>, Error>){
        return std::forward<L>(left);
    } else if constexpr (std::is_same_v<std::decay_t<R>, Error>){
        return std::forward<R>(right);
    } else {
        return op(std::forward<L>(left), std::forward<R>(right));
    }, lhs, rhs);
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.