ماذا قدم C++17؟ تحليل أبرز مستجدات المعيار
\n\nإذا كنت تكتب بلغة C++ وتريد البقاء في التيار الرئيسي، فإن C++17 هو الإصدار الذي يجب أن تتقنه الآن. تم إصداره في عام 2017، ولكن لا تزال العديد من المشاريع "عالقة" على C++14 أو حتى C++11، خوفًا من الانتقال إلى المعيار الجديد. وهذا خطأ.
\n\nفي هذه المقالة، سنقوم بتحليل ميزات C++17 الجديدة من خلال أمثلة واقعية. ستتعلم كيفية تبسيط الكود، والتخلص من الفحوصات غير الضرورية، وجعل البرامج أسرع. لن نقوم بإدراج جميع التغييرات البالغ عددها 105 - فقط ما سيفيدك حقًا في العمل.
\n\n1. الروابط الهيكلية (Structured Bindings) - التفكيك في ثانية
\n\nواحدة من أكثر ميزات C++17 ملاءمة هي الروابط الهيكلية. في السابق، لتفكيك tuple أو pair، كان عليك كتابة std::tie أو الوصول عبر الفهارس. الآن أصبح الأمر أكثر أناقة.
مثال: إرجاع قيم متعددة من دالة
\n\n#include <iostream>\n#include <tuple>\n#include <string>\n\nstd::tuple<int, std::string, double> getData() {\n return {42, "الإجابة", 3.14};\n}\n\nint main() {\n // C++17: سطر واحد بدلاً من std::tie\n auto [id, name, value] = getData();\n std::cout << name << ": " << id << " (" << value << ")\\n";\n return 0;\n}\n\nما الذي تغير؟ في السابق، كان عليك تعريف المتغيرات بشكل منفصل ثم استدعاء std::tie. الآن auto [a, b, c] يقوم بكل العمل نيابة عنك.
الروابط الهيكلية لا تعمل فقط مع tuples، بل أيضًا مع المصفوفات وأي هياكل تحتوي على حقول عامة. هذا أحد ابتكارات C++17 التي تجعل الكود أنظف وأكثر قابلية للقراءة.
\n\n2. std::optional - التخلص من القيم "السحرية"
\n\nكم مرة رأيت كودًا حيث ترجع الدالة -1 أو nullptr للإشارة إلى خطأ؟ أو الأسوأ من ذلك - علامة bool والنتيجة عبر مرجع؟ std::optional<T> يحل هذه المشكلة مرة واحدة وإلى الأبد.
مثال: بحث آمن في حاوية
\n\n#include <iostream>\n#include <optional>\n#include <map>\n#include <string>\n\nstd::optional<int> findValue(const std::map<std::string, int>& m, const std::string& key) {\n auto it = m.find(key);\n if (it != m.end()) {\n return it->second; // توجد قيمة\n }\n return std::nullopt; // لا توجد قيمة\n}\n\nint main() {\n std::map<std::string, int> ages = {{"Alice", 30}, {"Bob", 25}};\n \n auto result = findValue(ages, "Charlie");\n if (result) {\n std::cout << "تم العثور: " << *result << "\\n";\n } else {\n std::cout << "لم يتم العثور على المفتاح\\n";\n }\n \n // أو استخدم value_or للحصول على قيمة افتراضية\n int age = result.value_or(0);\n return 0;\n}\n\nstd::optional هو حاوية يمكن أن تحتوي على قيمة أو تكون فارغة. تتحقق منها عبر if (opt)، وتحصل على القيمة عبر *opt أو opt.value(). هذا أكثر أمانًا بكثير من أكواد الأخطاء "الاتفاقية".
3. if constexpr - قوالب بدون صداع
\n\nميزات C++17 الجديدة للبرمجة الفوقية هي مجرد هدية. if constexpr يسمح بتنفيذ التجميع الشرطي داخل القوالب دون بهلوانيات SFINAE.
مثال: دالة عالمية لأنواع مختلفة
\n\n#include <iostream>\n#include <type_traits>\n#include <string>\n\ntemplate <typename T>\nvoid printInfo(const T& value) {\n if constexpr (std::is_integral_v<T>) {\n std::cout << "عدد صحيح: " << value << "\\n";\n } else if constexpr (std::is_floating_point_v<T>) {\n std::cout << "عدد عائم: