optional, variant, any
Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan C++ di Coddy. Pelajaran 89 dari 104.
C++ modern menyediakan tiga tipe kosakata dalam header <optional>, <variant>, dan <any> yang membantumu menangani nilai yang mungkin tidak ada, dapat menyimpan salah satu dari beberapa tipe, atau dapat menyimpan tipe apa pun.
std::optional<T> merepresentasikan nilai yang mungkin ada atau tidak ada. Ini cocok untuk fungsi yang mungkin gagal tanpa melempar exception:
#include <iostream>
#include <optional>
std::optional<int> findIndex(const std::string& str, char c) {
for (size_t i = 0; i < str.size(); ++i) {
if (str[i] == c) return i;
}
return std::nullopt; // Tidak ada nilai
}
int main() {
auto result = findIndex("hello", 'l');
if (result.has_value()) {
std::cout << "Found at: " << *result << "\n"; // 2
}
}std::variant<Types...> adalah union yang aman terhadap tipe dan menyimpan tepat satu dari tipe yang ditentukan pada waktu tertentu:
#include <iostream>
#include <variant>
#include <string>
int main() {
std::variant<int, double, std::string> data;
data = 42;
std::cout << std::get<int>(data) << "\n";
data = "hello";
if (std::holds_alternative<std::string>(data)) {
std::cout << std::get<std::string>(data) << "\n";
}
}std::any dapat menyimpan nilai dengan tipe apa pun yang ditentukan saat runtime. Gunakan std::any_cast untuk mengambil nilainya:
#include <iostream>
#include <any>
int main() {
std::any value = 10;
std::cout << std::any_cast<int>(value) << "\n";
value = std::string("text");
std::cout << std::any_cast<std::string>(value) << "\n";
}Pilih std::optional untuk nilai yang dapat bernilai null, std::variant saat kamu mengetahui tipe yang mungkin saat compile, dan std::any hanya saat kamu benar-benar membutuhkan fleksibilitas tipe saat runtime.
Tantangan
MudahMari buat sistem konfigurasi yang menunjukkan keunggulan tipe kosakata C++ modern. Kamu akan membuat pengelola pengaturan fleksibel yang menangani nilai yang mungkin tidak ada, dapat menampung berbagai tipe, atau memerlukan fleksibilitas tipe saat runtime.
Kamu akan mengatur kodemu dalam tiga file:
ConfigTypes.h: Definisikan tipe nilai konfigurasi dan fungsi pembantu.Buat fungsi bernama
parseValueyang menerima string dan mencoba menguraikannya sebagai bilangan bulat. Jika string tersebut mewakili bilangan bulat yang valid, kembalikan bilangan bulat yang dibungkus dalamstd::optional. Jika penguraian gagal (string berisi karakter nonnumerik), kembalikanstd::nullopt. Sederhananya, anggap string valid jika hanya berisi digit (dan secara opsional diawali tanda minus).Buat juga alias tipe bernama
Settingmenggunakanstd::variantyang dapat menampungint,double, ataustd::string.Terakhir, buat fungsi bernama
describeSettingyang menerimaSettingdan mengembalikan string yang menjelaskan tipe yang ditampung serta nilainya dalam format ini:- Untuk int:
Integer: [value] - Untuk double:
Double: [value] - Untuk string:
String: [value]
- Untuk int:
DynamicStore.h: Buat penyimpanan key-value sederhana menggunakanstd::any.Definisikan class
DynamicStoreyang dapat menyimpan nilai dari tipe apa pun. Class ini harus memiliki:- Method
setyang menerima key string dan nilaistd::any, lalu menyimpannya secara internal (gunakanstd::map) - Method
getyang menerima key dan mengembalikan nilaistd::any(kembalikanstd::anykosong jika key tidak ada) - Method
hasKeyyang mengembalikan true jika key ada
- Method
main.cpp: Baca tiga input:- String yang mungkin berupa angka (untuk menguji
std::optional) - Penanda tipe:
int,double, ataustring - Nilai yang sesuai dengan tipe tersebut
Tunjukkan penggunaan ketiga tipe kosakata:
Pertama, gunakan fungsi
parseValuedengan input pertama. Jika input berisi nilai, cetakParsed: [value]. Jika kosong, cetakParse failed.Kedua, buat variant
Settingberdasarkan penanda tipe. Jika tipenyaint, simpan nilainya sebagai bilangan bulat. Jikadouble, simpan sebagai bilangan desimal. Jikastring, simpan sebagai string. Lalu panggildescribeSettingdan cetak hasilnya.Ketiga, buat
DynamicStore, simpan string"config_loaded"dengan key"status", lalu ambil kembali dan cetak:Status: [value]. Gunakanstd::any_cast<std::string>untuk mengambil nilainya.- String yang mungkin berupa angka (untuk menguji
Contohnya, dengan input 42, int, dan 100:
Parsed: 42
Integer: 100
Status: config_loadedDengan input hello, double, dan 3.14:
Parse failed
Double: 3.14
Status: config_loadedDengan input -15, string, dan username:
Parsed: -15
String: username
Status: config_loadedIngat untuk menyertakan header yang sesuai: <optional>, <variant>, <any>, <string>, dan <map> jika diperlukan. Gunakan std::holds_alternative dan std::get untuk menggunakan variant-mu, serta has_value() atau konversi boolean langsung untuk memeriksa optional-mu.
Coba sendiri
#include <iostream>
#include <string>
#include <any>
#include "ConfigTypes.h"
#include "DynamicStore.h"
int main() {
// Baca tiga input
std::string input1; // String yang mungkin berupa angka (untuk menguji std::optional)
std::string typeIndicator; // Penanda tipe: int, double, atau string
std::string value; // Nilai yang sesuai dengan tipe tersebut
std::cin >> input1;
std::cin >> typeIndicator;
std::cin >> value;
// TODO: Bagian 1: Uji std::optional dengan parseValue
// Gunakan fungsi parseValue dengan input1
// Jika berisi nilai, cetak "Parsed: [value]"
// Jika kosong, cetak "Parse failed"
// TODO: Bagian 2: Uji std::variant dengan Setting
// Buat variant Setting berdasarkan typeIndicator
// Jika tipenya "int", simpan nilai sebagai bilangan bulat
// Jika tipenya "double", simpan nilai sebagai double
// Jika tipenya "string", simpan nilai sebagai string
// Lalu panggil describeSetting dan cetak hasilnya
// TODO: Bagian 3: Uji std::any dengan DynamicStore
// Buat DynamicStore
// Simpan string "config_loaded" dengan kunci "status"
// Ambil nilainya dan cetak: "Status: [value]"
// Gunakan std::any_cast<std::string> untuk mengambil nilainya
return 0;
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Object
1Dasar-Dasar OOP
File EksternalBuild dan Kompilasi C++File Header dan File SourceNamespace dan CakupanPengantar OOP dalam C++class vs objectPointer 'this'method (Fungsi Anggota)Atribut (Anggota Data)Dasar Ctor dan DtorRingkasan: Kalkulator Sederhana4Properti class
Anggota instance vs staticGetter dan setterFungsi anggota constKata kunci mutableMethod dan variabel staticFungsi dan class friendRangkuman, Pengelola Rekening Bank7Pewarisan
Pewarisan DasarTingkat Akses pada PewarisanUrutan Pemanggilan Ctor & DtorPenimpaan methodFungsi Virtual & VTablePewarisan BergandaPewarisan VirtualRangkuman: Hierarki Karyawan2Manajemen Memori
Memori Stack vs HeapPointer dan ReferenceMemori Dinamis (new/delete)Smart Pointer di C++RAII di C++Rangkuman: Pengelola Array Dinamis5Enkapsulasi
Penentu Akses dalam C++Penentu Akses secara MendalamPenyembunyian Informasistruct vs classNested dan Inner classRangkuman, Sistem Catatan Siswa8Polimorfisme
Polimorfisme saat Compile vs RuntimeOverloading FungsiMeninjau Kembali Fungsi VirtualFungsi Virtual MurniKelas AbstrakDesain Interface di C++Casting Dinamis & RTTIRangkuman: Kalkulator Bentuk3Konstruktor & Destruktor
Konstruktor DefaultKonstruktor BerparameterKonstruktor SalinKonstruktor PindahDaftar Inisialisasi KonstruktorKonstruktor DelegasiKupas Tuntas DestruktorAturan Tiga, Lima, dan NolRangkuman: class String6Overloading Operator
Pengantar Overloading OperatorOverloading Operator AritmetikaOverloading Operator PerbandinganOperator StreamOverloading Operator PenugasanOverloading Operator [] dan ()Operator Konversi TipeRingkasan, class Matrix9Template
Template FungsiTemplate classSpesialisasi TemplateTemplate VariadikDasar SFINAE & Type TraitsRangkuman, Container Generik12Fitur Modern C++
Semantik Pemindahan & RvaluePenerusan SempurnaEkspresi Lambda secara Mendalamstd::function & std::bindconstexpr dan constevalPengikatan Terstrukturoptional, variant, anyLatihan sendiri: Compiler C++ online