C++ std:any examples

C Std Any Examples



בתכנות C++, 'std::any' מספריית התבניות הסטנדרטית (STL) מציג הקלדה דינמית לטיפול בנתונים הטרוגניים. שלא כמו קונטיינרים מסורתיים, 'std::any' מאפשר אחסון ערכים מכל סוג בתוך קונטיינר בודד, מה שמגביר את הגמישות בתרחישים שבהם סוגי הנתונים אינם ידועים או משתנים בזמן הריצה. גישה טיפוס-אגנוסטית זו מקדמת תכנות גנרי אשר מעצימה את המפתחים ליצור קוד מותאם ואקספרסיבי יותר תוך שמירה על בטיחות הסוג. בחקירה זו, נתעמק בתכונות של 'std::any', דפוסי השימוש שלו ודוגמאות מעשיות הממחישות את תפקידו בכתיבת קוד C++ חזק וגמיש.

דוגמה 1: שימוש בסיסי ב-Std::Any

ראשית, בואו נחקור דוגמה פשוטה כדי להדגים את השימוש הבסיסי של 'std::any'. שקול תרחיש שבו אתה צריך פונקציה כדי לקבל סוגים שונים של פרמטרים:







הנה קטע הקוד:



#include
#include

בטל תהליך כל ( const std::any & ערך ) {
אם ( value.has_value ( ) ) {
std::cout << 'סוג הערך המאוחסן:' << value.type ( ) .שֵׁם ( ) << std::endl;

אם ( value.type ( ) == סוג סוג ( int ) ) {
std::cout << 'ערך: ' << std::any_cast < int > ( ערך ) << std::endl;
} אַחֵר אם ( value.type ( ) == סוג סוג ( לְהַכפִּיל ) ) {
std::cout << 'ערך: ' << std::any_cast < לְהַכפִּיל > ( ערך ) << std::endl;
} אַחֵר אם ( value.type ( ) == סוג סוג ( std::string ) ) {
std::cout << 'ערך: ' << std::any_cast < std::string > ( ערך ) << std::endl;
} אַחֵר {
std::cout << 'סוג לא נתמך!' << std::endl;
}
} אַחֵר {
std::cout << 'אין ערך מאוחסן ב-std::any.' << std::endl;
}
}

int main ( ) {
לעבד כל ( 42 ) ;
לעבד כל ( 3.14 ) ;
לעבד כל ( std::string ( 'שלום, std::any!' ) ) ;
processAny ( 4.5f ) ; // אינו נתמך סוּג

לַחֲזוֹר 0 ;
}


בדוגמה זו, אנו מגדירים את הפונקציה 'processAny' שלוקחת הפניה 'std::any' כפרמטר ובוחנת את תוכנה. בתוך הפונקציה, אנו בודקים תחילה אם למשתנה 'std::any' יש ערך מאוחסן באמצעות has_value(). אם קיים ערך, אנו קובעים את סוג הערך המאוחסן באמצעות type().name() ונמשיך להדפיס את הערך המתאים על סמך הסוג שלו. לאחר מכן, הפונקציה הראשית מדגימה את התועלת של 'processAny' על ידי קריאה לה עם סוגים שונים: מספר שלם (42), כפול (3.14) ומחרוזת ('Hello, std::any!'). הפונקציה מטפלת כראוי בכל סוג ומדפיסה את הערכים המתאימים. עם זאת, כאשר מנסים לעבד מספר נקודה צפה (4.5f), שאינו נתמך בדוגמה זו, התוכנית מטפלת בחן במצב על ידי ציון שהסוג אינו נתמך.



הפלט שנוצר הוא:






זה מציג כיצד 'std::any' מאפשר טיפול דינמי בסוגי נתונים שונים, מה שהופך אותו לכלי רב-תכליתי לתכנות גנרי ב-C++.

דוגמה 2: אחסון הסוגים המוגדרים על ידי המשתמש

הדוגמה השנייה בוחנת כיצד סוג דינמי זה בתוך ספריית התבניות הסטנדרטית (STL) מתאים בצורה חלקה למבני הנתונים המותאמים אישית. בהתמקדות בסוג מוגדר על ידי המשתמש, מבנה הנקודה, אנו מציגים כיצד 'std::any' מטפל במופעים של מבנים כאלה.



הנה הקוד:

#include
#include

מחלקה MyClass {
פּוּמְבֵּי:
הכיתה שלי ( ערך int ) : נתונים ( ערך ) { }

void printData ( ) const {
std::cout << 'נתונים ב-MyClass: ' << נתונים << std::endl;
}

פְּרָטִי:
int נתונים;
} ;

int main ( ) {
std::any anyObject = MyClass ( 42 ) ;

אם ( anyObject.has_value ( ) ) {
אוטומטי & myClassInstance = std::any_cast < הכיתה שלי &> ( anyObject ) ;
myClassInstance.printData ( ) ;
} אַחֵר {
std::cout << 'אין ערך מאוחסן ב-std::any.' << std::endl;
}

לַחֲזוֹר 0 ;
}


בקטע קוד C++ זה, אנו יוצרים דוגמה פשוטה להמחשה באמצעות הסוג 'std::any' עם מחלקה מוגדרת על ידי משתמש בשם 'MyClass'. בתוך המחלקה, יש משתנה חבר פרטי שנקרא 'data' ושיטה ציבורית בשם printData() כדי להציג את הערך של הנתונים האלה. ערך מספר שלם מועבר ומוקצה לאיבר 'נתונים' בבנאי.

בפונקציה 'main', אנו מייצרים אובייקט של 'MyClass' עם ערך התחלתי של 42 ולאחר מכן מאחסנים אותו במשתנה 'std::any' בשם 'anyObject'. זה מדגים את היכולת של 'std::any' להחזיק את המופעים של מחלקות מוגדרות על ידי המשתמש.

לאחר מכן, אנו משתמשים במשפט 'if' כדי לבדוק אם ל-'anyObject' יש ערך באמצעות שיטת has_value() . אם יש ערך, אנו מאחזרים את האובייקט המאוחסן באמצעות 'std::any_cast'. ה-'std::any_cast' משמש עם ארגומנט התבנית 'MyClass&' כדי להטיל את האובייקט המאוחסן להפניה של 'MyClass'. הפניה זו, 'myClassInstance', משמשת לאחר מכן לקריאת שיטת printData(), ומציגה את היכולת לגשת ולפעול על הסוג המאוחסן המוגדר על ידי המשתמש בתוך ה-'std::any'.

אם לא מאוחסן ערך ב-'std::any', אנו מדפיסים הודעה המסמנת זאת. בדיקה מותנית זו מבטיחה שאנו מטפלים בתרחישים שבהם המשתנה 'std::any' עשוי להיות ריק.

הנה הפלט:

דוגמה 3: מיכל של סוגים מעורבים

בתכנות, 'מיכל מסוג מעורב' מתייחס למבנה נתונים המסוגל להכיל את האלמנטים של סוגי נתונים מגוונים, שעלולים להיות לא קשורים. גמישות זו היא בעלת ערך בעת התמודדות עם תרחישים שבהם סוגי הנתונים אינם ידועים בזמן ההידור או משתנים באופן דינמי במהלך הפעלת התוכנית. ב-C++, 'std::any' מדגים את המושג הזה, ומאפשר יצירת מיכל בודד לאחסון ערכים מסוגים שונים.

בואו נחקור תרחיש שבו אנו יוצרים מיכל שמכיל סוגים שונים:

#include
#include
#include

int main ( ) {

std::vector < std::any > mixedContainer;

mixedContainer.push_back ( 42 ) ;
mixedContainer.push_back ( 3.14 ) ;
mixedContainer.push_back ( std::string ( 'שלום' ) ) ;
mixedContainer.push_back ( נָכוֹן ) ;

ל ( const auto & אלמנט: mixedContainer ) {
אם ( element.type ( ) == סוג סוג ( int ) ) {
std::cout << 'מספר שלם: ' << std::any_cast < int > ( אֵלֵמֶנט ) << std::endl;
} אַחֵר אם ( element.type ( ) == סוג סוג ( לְהַכפִּיל ) ) {
std::cout << 'כפול:' << std::any_cast < לְהַכפִּיל > ( אֵלֵמֶנט ) << std::endl;
} אַחֵר אם ( element.type ( ) == סוג סוג ( std::string ) ) {
std::cout << 'מחרוזת:' << std::any_cast < std::string > ( אֵלֵמֶנט ) << std::endl;
} אַחֵר אם ( element.type ( ) == סוג סוג ( bool ) ) {
std::cout << 'בוליאני:' << std::any_cast < bool > ( אֵלֵמֶנט ) << std::endl;
} אַחֵר {
std::cout << 'סוג לא ידוע' << std::endl;
}
}

לַחֲזוֹר 0 ;
}


באיור זה, אנו מדגימים את הרעיון של מיכל מסוג מעורב באמצעות C++ והתכונה 'std::any'. אנו יוצרים את ה-'std::vector' בשם 'mixedContainer' כדי לשמש כמיכל שלנו כדי להחזיק את האלמנטים של סוגי נתונים שונים. באמצעות הפונקציה 'push_back', אנו מאכלסים את המיכל הזה באלמנטים שונים כולל מספר שלם (42), כפול (3.14), מחרוזת ('Hello') ובוליאני (true).

כאשר אנו חוזרים על 'mixedContainer' באמצעות לולאת 'for', אנו משתמשים בפונקציה type() כדי לזהות את סוג הנתונים של כל אלמנט באופן דינמי. באמצעות 'std::any_cast', אנו מחלצים ומדפיסים את הערכים המתאימים על סמך הסוגים שלהם. לדוגמה, אם האלמנט הוא מסוג 'int', אנו מדפיסים אותו כמספר שלם. אם הוא מסוג 'כפול', נדפיס אותו ככפול, וכן הלאה.

הנה הפלט שנוצר:

דוגמה 4: טיפול בשגיאות עם Std::Any

טיפול בשגיאות בעת שימוש ב-'std::any' כרוך בבדיקה אם הסוג נתמך או אם ערך מאוחסן. בדוגמה זו, אנו מדגימים כיצד לטפל בסוגים שאינם נתמכים:

#include
#include

int main ( ) {
std::any myAny = 42 ;

לְנַסוֹת {

ערך כפול = std::any_cast < לְהַכפִּיל > ( myAny ) ;
std::cout << 'ערך: ' << ערך << std::endl;
} לתפוס ( const std::bad_any_cast & זה ) {

std::cerr << 'שגיאה:' << ה.מה ( ) << std::endl;
}

לַחֲזוֹר 0 ;
}


נתחיל באתחול המשתנה 'std::any', 'myAny', עם הערך של 42 מסוג מספר שלם. בתוך בלוק ה-'try' שלאחר מכן, אנו עושים ניסיון מפורש להטיל ערך שלם זה ל-'double' באמצעות פעולת 'std::any_cast'. עם זאת, מכיוון שהסוג האמיתי המאוחסן ב-'myAny' הוא מספר שלם, פעולת ההטלה הזו אינה חוקית עבור 'כפול' מה שמוביל לסוג אי-התאמה.

כדי לנהל את השגיאה הפוטנציאלית הזו בחן, אנו מיישמים את הטיפול בחריגים עם בלוק 'catch' שנועד לתפוס את סוג החריגה הספציפי של 'std::bad_any_cast'. במקרה של ליהוק לא מוצלח, בלוק ה-'catch' מופעל ואנו יוצרים הודעת שגיאה באמצעות 'std::cerr' כדי להודיע ​​על אופי השגיאה. אסטרטגיית טיפול בשגיאות זו מבטיחה שהתוכנית שלנו תוכל להתמודד בחן במצבים שבהם ניסיון הטיפוס מתנגש עם הסוג האמיתי המאוחסן במשתנה 'std::any'.

סיכום

במאמר זה, חקרנו את היישומים של 'std::any' ב-C++, מיכל סוג דינמי שמוצג ב-C++ עבור ערכים מסוגים שונים. הדגמנו את הרבגוניות שלו באמצעות דוגמאות שונות, והצגנו תרחישים שנעים בין שימוש בסיסי לטיפול בסוגים המוגדרים על ידי המשתמש ובאוספים הטרוגניים. הדגמנו את היישום המעשי שלו בתרחישים שבהם סוג הנתונים אינו ידוע בזמן הקומפילציה. בנוסף, בדקנו את טכניקות הטיפול בשגיאות, תוך הדגשת החשיבות של ניהול בחן של הסוגים הלא נתמכים באמצעות טיפול בחריגים.