C++ std:any Παραδείγματα

C Std Any Paradeigmata



Στον προγραμματισμό C++, το 'std::any' από την Standard Template Library (STL) εισάγει μια δυναμική πληκτρολόγηση για το χειρισμό ετερογενών δεδομένων. Σε αντίθεση με τα παραδοσιακά κοντέινερ, το 'std::any' επιτρέπει την αποθήκευση των τιμών οποιουδήποτε τύπου σε ένα μόνο κοντέινερ, ενισχύοντας την ευελιξία σε σενάρια όπου οι τύποι δεδομένων είναι άγνωστοι ή ποικίλλουν κατά το χρόνο εκτέλεσης. Αυτή η τυπο-αγνωστική προσέγγιση προωθεί έναν γενικό προγραμματισμό που εξουσιοδοτεί τους προγραμματιστές να δημιουργήσουν έναν πιο προσαρμόσιμο και εκφραστικό κώδικα, διατηρώντας παράλληλα την ασφάλεια τύπου. Σε αυτήν την εξερεύνηση, θα εμβαθύνουμε στα χαρακτηριστικά του 'std::any', στα πρότυπα χρήσης του και πρακτικά παραδείγματα που απεικονίζουν τον ρόλο του στη σύνταξη ενός ισχυρού και ευέλικτου κώδικα C++.

Παράδειγμα 1: Βασική χρήση του Std::Any

Αρχικά, ας εξερευνήσουμε ένα απλό παράδειγμα για να δείξουμε τη βασική χρήση του 'std::any'. Εξετάστε ένα σενάριο όπου χρειάζεστε μια συνάρτηση για να αποδεχτείτε διάφορους τύπους παραμέτρων:







Εδώ είναι το απόσπασμα κώδικα:



#include
#include

άκυρη διαδικασία Οποιαδήποτε ( const std:: any & αξία ) {
αν ( αξία.έχει_τιμή ( ) ) {
std::cout << 'Τύπος αποθηκευμένης τιμής: ' << αξία.τύπος ( ) .όνομα ( ) << std::endl;

αν ( αξία.τύπος ( ) == δακτυλογραφημένο ( ενθ ) ) {
std::cout << 'Αξία: ' << std::any_cast < ενθ > ( αξία ) << std::endl;
} αλλού αν ( αξία.τύπος ( ) == δακτυλογραφημένο ( διπλό ) ) {
std::cout << 'Αξία: ' << std::any_cast < διπλό > ( αξία ) << std::endl;
} αλλού αν ( αξία.τύπος ( ) == δακτυλογραφημένο ( 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!' ) ) ;
διαδικασία Οποιοδήποτε ( 4,5 στ ) ; // Ανυποστήρικτος τύπος

ΕΠΙΣΤΡΟΦΗ 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 αξία ) : δεδομένα ( αξία ) { }

άκυρα δεδομένα εκτύπωσης ( ) συνθ {
std::cout << 'Δεδομένα στο MyClass: ' << δεδομένα << std::endl;
}

ιδιωτικός:
int δεδομένα?
} ;

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

αν ( anyObject.has_value ( ) ) {
αυτο & myClassInstance = std::any_cast < Η τάξη μου &> ( οποιοδήποτε αντικείμενο ) ;
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:: οποιαδήποτε > mixedContainer;

mixedContainer.push_back ( 42 ) ;
mixedContainer.push_back ( 3.14 ) ;
mixedContainer.push_back ( std::string ( 'Γειά σου' ) ) ;
mixedContainer.push_back ( αληθής ) ;

Για ( const auto & στοιχείο : mixedContainer ) {
αν ( στοιχείο.τύπος ( ) == δακτυλογραφημένο ( ενθ ) ) {
std::cout << 'Ακέραιος αριθμός:' << std::any_cast < ενθ > ( στοιχείο ) << std::endl;
} αλλού αν ( στοιχείο.τύπος ( ) == δακτυλογραφημένο ( διπλό ) ) {
std::cout << 'Διπλό:' << std::any_cast < διπλό > ( στοιχείο ) << std::endl;
} αλλού αν ( στοιχείο.τύπος ( ) == δακτυλογραφημένο ( std::string ) ) {
std::cout << 'Χορδή:' << std::any_cast < std::string > ( στοιχείο ) << std::endl;
} αλλού αν ( στοιχείο.τύπος ( ) == δακτυλογραφημένο ( bool ) ) {
std::cout << 'Boolean:' << std::any_cast < bool > ( στοιχείο ) << std::endl;
} αλλού {
std::cout << 'Άγνωστος τύπος' << std::endl;
}
}

ΕΠΙΣΤΡΟΦΗ 0 ;
}


Σε αυτήν την εικόνα, παρουσιάζουμε την έννοια ενός κοντέινερ μικτού τύπου χρησιμοποιώντας C++ και το χαρακτηριστικό 'std::any'. Δημιουργούμε το 'std::vector' με το όνομα 'mixedContainer' για να χρησιμεύσει ως το κοντέινερ μας για να κρατάμε τα στοιχεία διαφορετικών τύπων δεδομένων. Χρησιμοποιώντας τη συνάρτηση 'push_back', συμπληρώνουμε αυτό το κοντέινερ με διάφορα στοιχεία, όπως έναν ακέραιο αριθμό (42), ένα διπλό (3.14), μια συμβολοσειρά ('Hello') και ένα Boolean (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' για να επικοινωνήσουμε τη φύση του σφάλματος. Αυτή η στρατηγική διαχείρισης σφαλμάτων διασφαλίζει ότι το πρόγραμμά μας μπορεί να χειριστεί με χάρη τις καταστάσεις όπου το cast τύπου που επιχειρήθηκε συγκρούεται με τον πραγματικό τύπο που είναι αποθηκευμένος στη μεταβλητή 'std::any'.

συμπέρασμα

Σε αυτό το άρθρο, εξερευνήσαμε τις εφαρμογές του 'std::any' στη C++, ένα κοντέινερ δυναμικού τύπου που εισάγεται στη C++ για τιμές διαφορετικών τύπων. Αποδείξαμε την ευελιξία του μέσω διαφόρων παραδειγμάτων, παρουσιάζοντας σενάρια που κυμαίνονται από τη βασική χρήση έως το χειρισμό των τύπων που καθορίζονται από τον χρήστη και των ετερογενών συλλογών. Δείξαμε την πρακτική εφαρμογή του σε σενάρια όπου ο τύπος των δεδομένων δεν είναι γνωστός κατά το χρόνο μεταγλώττισης. Επιπλέον, διερευνήσαμε τις τεχνικές χειρισμού σφαλμάτων, τονίζοντας τη σημασία της χαριτωμένης διαχείρισης των μη υποστηριζόμενων τύπων μέσω του χειρισμού εξαιρέσεων.