Usando std::apply em std::expected em C++23

Usando std::apply em std::expected em C++23
Usando std::apply em std::expected em C++23

Simplificando o tratamento de erros em C++23

O tratamento eficaz de erros e o gerenciamento de valores de retorno são essenciais no desenvolvimento atual de C++. O método típico de trabalhar com funções que retornam tipos {std::expected} inclui muitas verificações e código de tratamento de erros, o que pode complicar a lógica e tornar o código mais difícil de manter.

Este artigo investiga o uso de um método mais sofisticado e geral para simplificar o gerenciamento de erros. Para reduzir o código padrão e melhorar a legibilidade, investigaremos a construção de um método `magic_apply` que agrega os resultados de muitos valores {std::expected} e os passa para outra função.

Comando Descrição
std::expected Um tipo de modelo usado em C++ para tratamento de erros que tem a capacidade de armazenar valores e erros.
std::unexpected Quando usado com std::expected, representa um valor de erro inesperado.
template<typename...> Descreve um modelo variado com uma quantidade infinita de argumentos de modelo que ele pode aceitar.
decltype Usado na programação de templates, principalmente para descobrir o tipo de expressão.
args.value() Se um objeto std::expected tiver um valor, acessa o valor contido nele.
args.has_value() Verifica se um valor está presente em um objeto std::expected.
(... && args.has_value()) Para determinar se cada objeto std::expected tem valores, dobre a expressão.
func(args.value()...) Usa os valores dos objetos std::expected para chamar o método func.
return unexpected<Err>(args.error()...) Retorna um erro inesperado contendo os erros dos objetos std::expected.

Gerenciamento eficaz de erros usando modelos variáveis

O std::expected type é usado nos scripts para facilitar o tratamento de erros em C++23. O objetivo principal é desenvolver uma função genérica chamada magic_apply que pode transmitir a saída de vários std::expected valores para outra função. Ao fazer isso, a tediosa verificação de erros que normalmente é necessária ao trabalhar com muitos std::expected valores são reduzidos. magic_apply é bastante flexível porque pode levar qualquer número de std::expected parâmetros utilizando modelos variados. Antes de chamar a função com o conteúdo de qualquer std::expected objeto, a lógica fundamental da magic_apply emprega uma expressão de dobra, (... && args.has_value()), para garantir que tudo std::expected objetos têm valores válidos.

Essa ideia é ilustrada no primeiro exemplo de script usando tipos simples como int e double. Ele define um compute_all função que realiza um cálculo básico, e getA e getB funções que retornam std::expected tipos. Se ambos os valores de getA e getB são legítimos, podemos chamar compute_all usando magic_apply; caso contrário, o erro é propagado. Ao reduzir o código clichê, esse método melhora a legibilidade e a facilidade de manutenção. Ideia semelhante é apresentada no segundo roteiro, mas para destacar a versatilidade da abordagem, string tipos e lambda functions são usados.

Reduzindo a complexidade no tratamento de erros C++ com `std::expected}

Script C++23 usando modelos variados

#include <expected>
#include <string>
#include <iostream>
#include <tuple>

using namespace std;

template<typename Func, typename... Args, typename Err>
auto magic_apply(Func func, const expected<Args, Err>&... args) -> expected<decltype(func(args.value()...)), Err> {
    if ((... && args.has_value())) {
        return func(args.value()...);
    } else {
        return unexpected<Err>(args.error()...);
    }
}

expected<int, string> getA(int x) {
    if (x > 0) return x;
    return unexpected<string>("Error in getA");
}

expected<double, string> getB(double y) {
    if (y > 0) return y;
    return unexpected<string>("Error in getB");
}

double compute_all(int a, double b) {
    return a + b;
}

int main() {
    auto result = magic_apply(compute_all, getA(10), getB(20.5));
    if (result) {
        cout << "Result: " << result.value() << endl;
    } else {
        cout << "Error: " << result.error() << endl;
    }
    return 0;
}

Combinando valores C++23 de resultados {std::expected} diferentes

Script C++23 usando funções Lambda

#include <expected>
#include <string>
#include <iostream>

using namespace std;

template<typename Func, typename... Args, typename Err>
auto magic_apply(Func func, const expected<Args, Err>&... args) -> expected<decltype(func(args.value()...)), Err> {
    bool all_valid = (args.has_value() && ...);
    if (all_valid) {
        return func(args.value()...);
    } else {
        return unexpected<Err>(args.error()...);
    }
}

expected<string, string> getA(bool flag) {
    if (flag) return "SuccessA";
    return unexpected<string>("Failed A");
}

expected<string, string> getB(bool flag) {
    if (flag) return "SuccessB";
    return unexpected<string>("Failed B");
}

string compute_all(const string& a, const string& b) {
    return a + " and " + b;
}

int main() {
    auto result = magic_apply(compute_all, getA(true), getB(true));
    if (result) {
        cout << "Result: " << result.value() << endl;
    } else {
        cout << "Error: " << result.error() << endl;
    }
    return 0;
}

Melhorando o tratamento de erros C++ com modelos variados

A capacidade de std::expected melhorar significativamente o tratamento de erros em sistemas complexos é outro benefício crucial de empregá-lo em C++. Combinar perfeitamente os resultados de muitas ações assíncronas é essencial em situações em que elas produzem std::expected tipos. Além de tornar o código mais simples, esse método garante um forte tratamento de erros. Funções mais versáteis e genéricas podem ser criadas combinando um número arbitrário de std::expected valores com variadic templates.

A versatilidade de magic_apply permite que ele seja usado com funções que aceitam vários tipos de argumentos. A implementação é ainda mais simplificada utilizando decltype, que deduz automaticamente o tipo de retorno da chamada de função combinada. Além disso, esta técnica pode ser expandida para gerenciar tarefas mais complexas, incluindo a fusão std::expected valores com outros tipos de erro ou alterando os valores antes de enviá-los para a função. Devido à sua adaptabilidade, o padrão pode ser usado para uma ampla gama de tarefas, desde cálculos simples até operações complexas.

Perguntas frequentes sobre modelos variados e std::expected

  1. O que é std::expected?
  2. É um tipo de modelo C++ que pode conter um erro ou um valor válido e é usado para gerenciamento de erros.
  3. Como é que magic_apply trabalhar?
  4. Elimina a necessidade de repetidas verificações de erros, combinando os resultados de numerosos std::expected valores e passá-los para uma função.
  5. O que são modelos variados?
  6. Os modelos de variáveis ​​oferecem uma grande liberdade no design de funções, permitindo que as funções aceitem um número arbitrário de parâmetros.
  7. Por que usar decltype em magic_apply?
  8. Utilizando os valores do std::expected objetos para determinar automaticamente o tipo de retorno da função que está sendo chamada.
  9. É magic_apply capaz de lidar com vários tipos de erros?
  10. Sim, pode ser feito para funcionar com std::expected valores com vários tipos de erros com alguns ajustes.
  11. Quais vantagens a utilização std::expected oferecer?
  12. Ao lidar com erros, oferece uma abordagem mais expressiva e limpa do que técnicas mais convencionais, como exceções ou códigos de retorno.
  13. É std::unexpected parte de std::expected?
  14. Além de std::expected, std::unexpected na verdade, representa um valor incorreto.
  15. As ações assíncronas podem ser utilizadas com magic_apply?
  16. Na verdade, é adaptável para lidar std::expected valores retornados por operações assíncronas.
  17. O que é uma expressão dobrada?
  18. Aqui, o recurso em C++ chamado expressão fold é usado para verificar se todos std::expected objetos contêm valores válidos de maneira simples.

Concluindo:

Em C++23, implementar uma função genérica para lidar com vários valores std::expected melhora muito a legibilidade do código e simplifica muito o tratamento de erros. A função magic_apply reduz o código clichê e melhora a capacidade de manutenção usando modelos variados para garantir que todos os valores previstos estejam corretos antes do processamento. Este método oferece uma solução flexível que pode ser aplicada a diferentes situações e oferece à programação C++ moderna uma maneira mais limpa e eficaz de lidar com falhas.