Effektivisera felhantering i C++23
Att effektivt hantera misstag och hantera avkastningsvärden är avgörande i dagens C++-utveckling. Den typiska metoden att arbeta med funktioner som returnerar {std::expected}-typer inkluderar många kontroller och felhanteringskod, vilket kan komplicera logiken och göra koden svårare att underhålla.
Denna artikel undersöker användningen av en mer sofistikerad och generell metod för att förenkla felhantering. För att minska koden och förbättra läsbarheten kommer vi att undersöka att konstruera en `magic_apply`-metod som aggregerar resultaten av många {std::expected}-värden och skickar dem till en annan funktion.
Kommando | Beskrivning |
---|---|
std::expected | En malltyp som används i C++ för felhantering som har möjlighet att lagra både värden och fel. |
std::unexpected | När det används med std::expected representerar det ett oväntat felvärde. |
template<typename...> | Skisserar en variadisk mall med en oändlig mängd mallargument som den kan acceptera. |
decltype | Används vid mallprogrammering, speciellt för att ta reda på typen av uttryck. |
args.value() | Om ett std::expected objekt har ett värde, kommer åt värdet som finns i det. |
args.has_value() | Verifierar om ett värde finns i ett std::expected objekt. |
(... && args.has_value()) | För att avgöra om varje std::expected objekt har värden, vik uttrycket. |
func(args.value()...) | Använder värdena för std::expected-objekten för att anropa metoden func. |
return unexpected<Err>(args.error()...) | Returnerar ett oväntat fel som innehåller felen från std::expected-objekten. |
Effektiv felhantering med hjälp av variabelmallar
De std::expected typ används i skripten för att underlätta felhanteringen i C++23. Huvudmålet är att utveckla en generisk funktion som kallas magic_apply som kan överföra resultatet från flera std::expected värden till en annan funktion. Genom att göra detta, den tråkiga felkontrollen som vanligtvis är nödvändig när man arbetar med många std::expected värden reduceras. magic_apply är ganska flexibel eftersom det kan ta hur många som helst std::expected parametrar genom att använda variadiska mallar. Innan du anropar funktionen med innehållet i ev std::expected objekt, den grundläggande logiken i magic_apply använder ett veckuttryck, (... && args.has_value()), för att se till att allt std::expected objekt har giltiga värden.
Denna idé illustreras i det första skriptexemplet med enkla typer som t.ex int och double. Den definierar en compute_all funktion som utför en grundläggande beräkning, och getA och getB funktioner som återkommer std::expected typer. Om båda värdena från getA och getB är legitima kan vi ringa compute_all använder magic_apply; om inte, sprids felet. Genom att reducera boilerplate-koden förbättrar denna metod läsbarheten och underhållbarheten. En liknande idé presenteras i det andra manuset, men för att belysa tillvägagångssättets mångsidighet, string typer och lambda functions används.
Minska komplexiteten i C++ felhantering med `std::expected}
C++23-skript som använder Variadic-mallar
#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;
}
Kombinera olika {std::expected} resultat C++23 värden
C++23-skript som använder lambdafunktioner
#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;
}
Förbättra C++-felhantering med Variadic-mallar
Kapaciteten hos std::expected att avsevärt förbättra felhanteringen i invecklade system är en annan avgörande fördel med att använda det i C++. Att kombinera resultaten av många asynkrona åtgärder sömlöst är viktigt i situationer när de ger resultat std::expected typer. Förutom att göra koden enklare garanterar denna metod en stark felhantering. Mer mångsidiga och generiska funktioner kan skapas genom att kombinera ett godtyckligt antal std::expected värden med variadic templates.
Mångsidigheten hos magic_apply gör att den kan användas med funktioner som tar in en mängd olika argumenttyper. Implementeringen görs ytterligare enklare genom att använda decltype, som automatiskt härleder returtypen för det kombinerade funktionsanropet. Dessutom kan denna teknik utökas för att hantera mer komplicerade uppgifter, inklusive sammanslagning std::expected värden med andra feltyper eller ändra värdena innan de skickas till funktionen. På grund av dess anpassningsförmåga kan mönstret användas för ett brett spektrum av uppgifter, från enkla beräkningar till komplexa operationer.
Vanliga frågor om Variadic-mallar och std::expected
- Vad är std::expected?
- Det är en C++-malltyp som kan innehålla ett fel eller ett giltigt värde och används för felhantering.
- Hur gör magic_apply arbete?
- Det eliminerar behovet av upprepade felkontroller genom att kombinera resultaten från många std::expected värden och skicka dem till en funktion.
- Vad är variadiska mallar?
- Variabla mallar erbjuder en stor del av friheten i funktionsdesign genom att göra det möjligt för funktioner att acceptera ett godtyckligt antal parametrar.
- Varför använda decltype i magic_apply?
- Att använda värdena för std::expected objekt för att automatiskt bestämma returtypen för den funktion som anropas.
- är magic_apply kan hantera olika feltyper?
- Ja, den kan göras för att fungera med std::expected värden har olika feltyper med några få justeringar.
- Vilka fördelar använder man std::expected erbjuda?
- Vid hantering av misstag erbjuder det ett mer uttrycksfullt och renare tillvägagångssätt än med mer konventionella tekniker som undantag eller returkoder.
- är std::unexpected del av std::expected?
- Förutom std::expected, std::unexpected representerar i själva verket ett felaktigt värde.
- Kan asynkrona åtgärder användas med magic_apply?
- Den är verkligen anpassningsbar att hantera std::expected värden som returneras av asynkrona operationer.
- Vad är ett veckuttryck?
- Här används funktionen i C++ som kallas fold expression för att kontrollera om alla std::expected objekt innehåller giltiga värden på ett enkelt sätt.
Avslutning:
I C++23 förbättrar implementering av en generisk funktion för att hantera flera std::expected värden avsevärt kodens läsbarhet och förenklar felhanteringen avsevärt. Funktionen magic_apply reducerar boilerplate-koden och förbättrar underhållsbarheten genom att använda variadic-mallar för att säkerställa att alla förväntade värden är korrekta före bearbetning. Denna metod erbjuder en flexibel lösning som kan appliceras på olika situationer och ger modern C++-programmering ett renare och mer effektivt sätt att hantera fel.