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
- O que é std::expected?
- É um tipo de modelo C++ que pode conter um erro ou um valor válido e é usado para gerenciamento de erros.
- Como é que magic_apply trabalhar?
- Elimina a necessidade de repetidas verificações de erros, combinando os resultados de numerosos std::expected valores e passá-los para uma função.
- O que são modelos variados?
- 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.
- Por que usar decltype em magic_apply?
- Utilizando os valores do std::expected objetos para determinar automaticamente o tipo de retorno da função que está sendo chamada.
- É magic_apply capaz de lidar com vários tipos de erros?
- Sim, pode ser feito para funcionar com std::expected valores com vários tipos de erros com alguns ajustes.
- Quais vantagens a utilização std::expected oferecer?
- 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.
- É std::unexpected parte de std::expected?
- Além de std::expected, std::unexpected na verdade, representa um valor incorreto.
- As ações assíncronas podem ser utilizadas com magic_apply?
- Na verdade, é adaptável para lidar std::expected valores retornados por operações assíncronas.
- O que é uma expressão dobrada?
- 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.