Effektivisering av feilhåndtering i C++23
Effektiv håndtering av feil og håndtering av avkastningsverdier er avgjørende i dagens C++-utvikling. Den typiske metoden for å jobbe med funksjoner som returnerer {std::expected}-typer inkluderer mange kontroller og feilhåndteringskode, som kan komplisere logikken og gjøre koden vanskeligere å vedlikeholde.
Denne artikkelen undersøker bruken av en mer sofistikert og generell metode for å forenkle feilhåndtering. For å redusere standardkode og forbedre lesbarheten, vil vi undersøke å konstruere en `magic_apply`-metode som samler resultatene av mange {std::expected} verdier og sender dem til en annen funksjon.
Kommando | Beskrivelse |
---|---|
std::expected | En maltype som brukes i C++ for feilhåndtering som har mulighet til å lagre både verdier og feil. |
std::unexpected | Når brukt med std::expected, representerer en uventet feilverdi. |
template<typename...> | Skisserer en variadisk mal med en uendelig mengde malargumenter som den kan akseptere. |
decltype | Brukes i malprogrammering, spesielt for å finne ut type uttrykk. |
args.value() | Hvis et std::expected-objekt har en verdi, får du tilgang til verdien i det. |
args.has_value() | Verifiserer om en verdi er tilstede i et std::expected objekt. |
(... && args.has_value()) | For å finne ut om hvert std::expected objekt har verdier, brett uttrykket. |
func(args.value()...) | Bruker verdiene til std::expected-objektene til å kalle metoden func. |
return unexpected<Err>(args.error()...) | Returnerer en uventet feil som inneholder feilene fra std::expected-objektene. |
Effektiv feilhåndtering ved bruk av variable maler
De std::expected type brukes i skriptene for å lette feilhåndtering i C++23. Hovedmålet er å utvikle en generisk funksjon kalt magic_apply som kan overføre utdata fra flere std::expected verdier til en annen funksjon. Ved å gjøre dette, den kjedelige feilkontrollen som vanligvis er nødvendig når man jobber med mange std::expected verdiene reduseres. magic_apply er ganske fleksibel fordi det kan ta et hvilket som helst antall std::expected parametere ved å bruke variadiske maler. Før du kaller opp funksjonen med innholdet i evt std::expected objekt, den grunnleggende logikken til magic_apply bruker et fold-uttrykk, (... && args.has_value()), for å sikre at alle std::expected objekter har gyldige verdier.
Denne ideen er illustrert i det første skripteksemplet ved å bruke enkle typer som f.eks int og double. Den definerer en compute_all funksjon som utfører en grunnleggende beregning, og getA og getB funksjoner som kommer tilbake std::expected typer. Hvis begge verdiene fra getA og getB er legitime, kan vi ringe compute_all bruker magic_apply; hvis ikke, spres feilen. Ved å redusere boilerplate-koden forbedrer denne metoden lesbarheten og vedlikeholdsevnen. En lignende idé presenteres i det andre manuset, men for å fremheve tilnærmingens allsidighet, string typer og lambda functions brukes.
Reduserer kompleksiteten i C++ feilhåndtering med `std::expected}
C++23-skript som bruker variadiske maler
#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;
}
Kombinere forskjellige {std::expected} resultater C++23-verdier
C++23-skript som bruker lambda-funksjoner
#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;
}
Forbedre C++-feilhåndtering med Variadic-maler
Kapasiteten til std::expected Å forbedre feilhåndteringen i intrikate systemer er en annen viktig fordel ved å bruke det i C++. Å kombinere resultatene av mange asynkrone handlinger sømløst er avgjørende i situasjoner når de gir resultat std::expected typer. I tillegg til å gjøre koden enklere, garanterer denne metoden sterk feilhåndtering. Mer allsidige og generiske funksjoner kan opprettes ved å kombinere et vilkårlig antall std::expected verdier med variadic templates.
Allsidigheten til magic_apply lar den brukes med funksjoner som tar inn en rekke argumenttyper. Implementeringen gjøres ytterligere enklere ved å utnytte decltype, som automatisk trekker returtypen til det kombinerte funksjonskallet. Videre kan denne teknikken utvides til å håndtere mer intrikate oppgaver, inkludert sammenslåing std::expected verdier med andre feiltyper eller endre verdiene før de sendes til funksjonen. På grunn av tilpasningsevnen kan mønsteret brukes til et bredt spekter av oppgaver, fra enkle beregninger til komplekse operasjoner.
Ofte stilte spørsmål om Variadic-maler og std::expected
- Hva er std::expected?
- Det er en C++-maltype som kan inneholde en feil eller en gyldig verdi og brukes til feilhåndtering.
- Hvordan gjør det magic_apply arbeid?
- Det eliminerer behovet for gjentatte feilkontroller ved å kombinere resultatene fra mange std::expected verdier og overføre dem til en funksjon.
- Hva er variadiske maler?
- Variable maler gir en stor del frihet i funksjonsdesign ved å gjøre det mulig for funksjoner å akseptere et vilkårlig antall parametere.
- Hvorfor bruke decltype i magic_apply?
- Bruke verdiene til std::expected objekter for automatisk å bestemme returtypen til funksjonen som kalles.
- Er magic_apply i stand til å håndtere ulike feiltyper?
- Ja, den kan lages for å fungere med std::expected verdier som har forskjellige feiltyper med noen få justeringer.
- Hvilke fordeler har å utnytte std::expected tilby?
- Når du håndterer feil, tilbyr den en mer uttrykksfull og renere tilnærming enn med mer konvensjonelle teknikker som unntak eller returkoder.
- Er std::unexpected del av std::expected?
- I tillegg til std::expected, std::unexpected representerer faktisk en feil verdi.
- Kan asynkrone handlinger utnyttes med magic_apply?
- Det er faktisk tilpasningsdyktig å håndtere std::expected verdier returnert av asynkrone operasjoner.
- Hva er et fold-uttrykk?
- Her brukes funksjonen i C++ kalt fold-uttrykk for å sjekke om alle std::expected objekter inneholder gyldige verdier på en enkel måte.
Avslutning:
I C++23 vil implementering av en generisk funksjon for å håndtere flere std::expected verdier forbedre kodens lesbarhet og i stor grad forenkle feilhåndtering. Magic_apply-funksjonen reduserer boilerplate-koden og forbedrer vedlikeholdsevnen ved å bruke variadiske maler for å sikre at alle forventede verdier er korrekte før behandling. Denne metoden tilbyr en fleksibel løsning som kan brukes i forskjellige situasjoner og gir moderne C++-programmering en renere og mer effektiv måte å håndtere feil på.