تبسيط معالجة الأخطاء في C++23
يعد التعامل مع الأخطاء وإدارة قيم الإرجاع بشكل فعال أمرًا ضروريًا في تطوير C++ اليوم. تتضمن الطريقة النموذجية للعمل مع الوظائف التي تُرجع الأنواع {std::expected} الكثير من عمليات التحقق ورموز معالجة الأخطاء، مما قد يؤدي إلى تعقيد المنطق ويجعل صيانة التعليمات البرمجية أكثر صعوبة.
تبحث هذه الورقة في استخدام طريقة أكثر تعقيدًا وعامة لتبسيط إدارة الأخطاء. من أجل تقليل التعليمات البرمجية المعيارية وتحسين إمكانية القراءة، سندرس إنشاء طريقة `magic_apply` التي تجمع نتائج العديد من قيم {std::expected} وتمريرها إلى وظيفة أخرى.
يأمر | وصف |
---|---|
std::expected | نوع القالب المستخدم في لغة C++ لمعالجة الأخطاء وله القدرة على تخزين كل من القيم والأخطاء. |
std::unexpected | عند استخدامه مع std::expected، فإنه يمثل قيمة خطأ غير متوقعة. |
template<typename...> | يحدد قالبًا متنوعًا بكمية لا حصر لها من وسائط القالب التي يمكنه قبولها. |
decltype | يستخدم في برمجة القوالب وخاصة لمعرفة نوع التعبير. |
args.value() | إذا كان للكائن std::expected قيمة، فإنه يصل إلى القيمة الموجودة فيه. |
args.has_value() | التحقق من وجود قيمة في كائن std::expected. |
(... && args.has_value()) | لتحديد ما إذا كان كل كائن std::expected له قيم أم لا، قم بطي التعبير. |
func(args.value()...) | يستخدم قيم الكائنات std::expected لاستدعاء الطريقة func. |
return unexpected<Err>(args.error()...) | إرجاع خطأ غير متوقع يحتوي على الأخطاء من الكائنات std::expected. |
الإدارة الفعالة للأخطاء باستخدام القوالب المتغيرة
ال std::expected يتم استخدام النوع في البرامج النصية لتسهيل معالجة الأخطاء في C++ 23. الهدف الرئيسي هو تطوير وظيفة عامة تسمى magic_apply التي يمكن أن تنقل إخراج عدة std::expected القيم إلى وظيفة أخرى. من خلال القيام بذلك، يتم التحقق من الأخطاء المملة التي عادة ما تكون ضرورية عند العمل مع الكثيرين std::expected يتم تقليل القيم. magic_apply مرن للغاية لأنه قد يستغرق أي عدد من std::expected المعلمات باستخدام قوالب Variadic. قبل استدعاء الوظيفة بمحتويات أي std::expected كائن، المنطق الأساسي ل magic_apply يستخدم تعبير أضعاف، (... && args.has_value())، للتأكد من كل شيء std::expected الكائنات لها قيم صالحة.
تم توضيح هذه الفكرة في المثال النصي الأول باستخدام أنواع بسيطة مثل int و double. ويحدد أ compute_all الوظيفة التي تنفذ العمليات الحسابية الأساسية، و getA و getB الوظائف التي تعود std::expected أنواع. إذا كانت كلتا القيمتين من getA و getB شرعية، يمكننا أن ندعو compute_all استخدام magic_apply; إذا لم يكن الأمر كذلك، فسيتم نشر الخطأ. من خلال تقليل التعليمات البرمجية المعيارية، تعمل هذه الطريقة على تحسين إمكانية القراءة وقابلية الصيانة. يتم تقديم فكرة مماثلة في النص الثاني، ولكن لتسليط الضوء على تنوع النهج، string أنواع و lambda functions تستخدم.
تقليل التعقيد في معالجة أخطاء C++ باستخدام `std::expected}
البرنامج النصي C++23 باستخدام قوالب Variadic
#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;
}
الجمع بين قيم {std::expected} المختلفة لقيم C++23
البرنامج النصي C++23 باستخدام وظائف 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;
}
تحسين معالجة أخطاء C++ باستخدام القوالب المتغيرة
قدرة std::expected يعد تحسين معالجة الأخطاء بشكل كبير في الأنظمة المعقدة فائدة مهمة أخرى لاستخدامها في لغة C++. يعد الجمع بين نتائج العديد من الإجراءات غير المتزامنة بسلاسة أمرًا ضروريًا في المواقف التي تؤدي فيها إلى نتائج std::expected أنواع. بالإضافة إلى جعل التعليمات البرمجية أبسط، تضمن هذه الطريقة معالجة قوية للأخطاء. يمكن إنشاء وظائف أكثر تنوعًا وعامة من خلال الجمع بين عدد عشوائي من std::expected القيم مع variadic templates.
تعدد الاستخدامات magic_apply يسمح باستخدامه مع الوظائف التي تأخذ مجموعة متنوعة من أنواع الوسائط. أصبح التنفيذ أكثر بساطة من خلال الاستفادة decltype، والذي يستنتج تلقائيًا نوع الإرجاع لاستدعاء الوظيفة المدمجة. علاوة على ذلك، يمكن توسيع هذه التقنية لإدارة المهام الأكثر تعقيدًا، بما في ذلك الدمج std::expected القيم مع أنواع الأخطاء الأخرى أو تغيير القيم قبل إرسالها إلى الوظيفة. ونظرًا لقدرته على التكيف، يمكن استخدام النموذج لمجموعة واسعة من المهام، بدءًا من الحسابات المباشرة وحتى العمليات المعقدة.
الأسئلة المتداولة حول قوالب Variadic وstd::expected
- ما هو std::expected؟
- إنه نوع قالب C++ يمكنه الاحتفاظ بخطأ أو قيمة صالحة ويستخدم لإدارة الأخطاء.
- كيف magic_apply عمل؟
- إنه يلغي الحاجة إلى عمليات التحقق من الأخطاء المتكررة من خلال الجمع بين نتائج عديدة std::expected القيم وتمريرها إلى وظيفة.
- ما هي القوالب المتنوعة؟
- توفر القوالب المتغيرة قدرًا كبيرًا من الحرية في تصميم الوظائف من خلال تمكين الوظائف من قبول عدد عشوائي من المعلمات.
- لماذا تستخدم decltype في magic_apply؟
- الاستفادة من قيم std::expected كائنات لتحديد نوع الإرجاع للوظيفة التي يتم استدعاؤها تلقائيًا.
- يكون magic_apply قادر على التعامل مع أنواع الأخطاء المختلفة؟
- نعم، يمكن جعله يعمل مع std::expected القيم التي تحتوي على أنواع أخطاء مختلفة مع بعض التعديلات.
- ما هي المزايا التي يستخدمها std::expected يعرض؟
- عند التعامل مع الأخطاء، فإنه يوفر أسلوبًا أكثر تعبيرًا ونظافة من الأساليب التقليدية مثل الاستثناءات أو رموز الإرجاع.
- يكون std::unexpected جزء من std::expected؟
- بالإضافة إلى std::expected, std::unexpected في الواقع، يمثل قيمة غير صحيحة.
- هل يمكن استخدام الإجراءات غير المتزامنة مع magic_apply؟
- إنها بالفعل قابلة للتكيف في التعامل معها std::expected القيم التي يتم إرجاعها بواسطة العمليات غير المتزامنة.
- ما هو التعبير أضعاف؟
- هنا، يتم استخدام الميزة الموجودة في C++ والتي تسمى تعبير الطي للتحقق مما إذا كان كل شيء std::expected تحتوي الكائنات على قيم صالحة بطريقة بسيطة.
الختام:
في C++ 23، يؤدي تنفيذ وظيفة عامة للتعامل مع قيم std::expected المتعددة إلى تحسين إمكانية قراءة التعليمات البرمجية بشكل كبير وتبسيط معالجة الأخطاء بشكل كبير. تعمل وظيفة Magic_apply على تقليل التعليمات البرمجية النمطية وتعزيز إمكانية الصيانة باستخدام قوالب متنوعة للتأكد من صحة جميع القيم المتوقعة قبل المعالجة. توفر هذه الطريقة حلاً مرنًا يمكن تطبيقه على مواقف مختلفة وتمنح برمجة C++ الحديثة طريقة أكثر نظافة وفعالية للتعامل مع حالات الفشل.