@@ -65,43 +65,58 @@ Aha, I hear you say, we can create an interface class and store pointers to obje
6565
6666Indeed, we can create a class, say ` Saveable ` , that has a single pure ` virtual ` function ` Save ` . We can then inherit from this class in our ` PngImage ` and ` JpegImage ` that override ` Save ` with their respective implementations:
6767
68+ <!--
69+ ` CPP_SETUP_START `
70+
71+ struct Noncopyable {
72+ Noncopyable() = default;
73+ Noncopyable(const Noncopyable&) = delete;
74+ Noncopyable(Noncopyable&&) = delete;
75+ Noncopyable& operator=(const Noncopyable&) = delete;
76+ Noncopyable& operator=(Noncopyable&&) = delete;
77+ };
78+
79+ $PLACEHOLDER
80+ ` CPP_SETUP_END `
81+ ` CPP_COPY_SNIPPET ` variant_images/main.cpp
82+ ` CPP_RUN_CMD ` CWD: variant_images c++ -std=c++17 main.cpp
83+ -->
6884``` cpp
6985#include < iostream>
7086#include < memory>
7187#include < string>
7288#include < vector>
7389
7490// 💡 See lecture on inheritance for Noncopyable implementation.
75- struct Saveable : public Noncopyable {
76- virtual void Save(const std::string& file_name) const = 0;
77- virtual ~ Saveable() = default;
91+ struct Saveable {
92+ virtual void Save(const std::string& file_name) const = 0;
93+ virtual ~ Saveable() = default;
7894};
7995
8096struct PngImage : public Saveable {
81- void Save(const std::string& file_name) const override {
82- std::cout << "Saving " << file_name << ".png\n";
83- }
84- // Some private image data would go here.
97+ void Save(const std::string& file_name) const override {
98+ std::cout << "Saving " << file_name << ".png\n";
99+ }
100+ // Some private image data would go here.
85101};
86102
87103struct JpegImage : public Saveable {
88- void Save(const std::string& file_name) const override {
89- std::cout << "Saving " << file_name << ".jpg\n";
90- }
91- // Some private image data would go here.
104+ void Save(const std::string& file_name) const override {
105+ std::cout << "Saving " << file_name << ".jpg\n";
106+ }
107+ // Some private image data would go here.
92108};
93109
94110void SaveImage(const Saveable& image, const std::string& file_name) {
95- image.Save(file_name);
111+ image.Save(file_name);
96112}
97113
98114int main() {
99- // A bunch of images that could be put here at runtime.
100- const std::vector< std::unique_ptr<Saveable > > images {
101- std::make_unique<PngImage >(),
102- std::make_unique<JpegImage >()
103- };
104- for (const auto& image : images) SaveImage(* image, "output");
115+ // A bunch of images that could be put here at runtime.
116+ std::vector< std::unique_ptr<Saveable > > images;
117+ images.push_back(std::make_unique<PngImage >());
118+ images.push_back(std::make_unique<JpegImage >());
119+ for (const auto& image : images) SaveImage(* image, "output");
105120}
106121```
107122
@@ -119,28 +134,28 @@ This is where `std::variant` comes to the rescue. It allows us to keep using tem
119134#include <vector>
120135
121136struct PngImage {
122- void Save(const std::string& file_name) const {
123- std::cout << "Saving " << file_name << ".png\n";
124- }
125- // Some private image data would go here.
137+ void Save(const std::string& file_name) const {
138+ std::cout << "Saving " << file_name << ".png\n";
139+ }
140+ // Some private image data would go here.
126141};
127142
128143struct JpegImage {
129- void Save(const std::string& file_name) const {
130- std::cout << "Saving " << file_name << ".jpg\n";
131- }
132- // Some private image data would go here.
144+ void Save(const std::string& file_name) const {
145+ std::cout << "Saving " << file_name << ".jpg\n";
146+ }
147+ // Some private image data would go here.
133148};
134149
135150using Image = std::variant<PngImage, JpegImage>;
136151
137152void SaveImage(const Image& image, const std::string& file_name) {
138- std::visit([&](const auto& img) { img.Save(file_name); }, image);
153+ std::visit([&](const auto& img) { img.Save(file_name); }, image);
139154}
140155
141156int main() {
142- const std::vector<Image> images = {PngImage{}, JpegImage{}};
143- for (const auto& image : images) SaveImage(image, "output");
157+ const std::vector<Image> images = {PngImage{}, JpegImage{}};
158+ for (const auto& image : images) SaveImage(image, "output");
144159}
145160```
146161
@@ -163,7 +178,7 @@ int main() {
163178 std::variant<int, std::string> value{};
164179 // By default, variant stores a value of the first type.
165180 std::cout << "Integer: " << std::get<int >(value) << '\n';
166- value = "Hello, variant!" // Value now holds a std:: string.
181+ value = "Hello, variant!"; // Value now holds a string.
167182 std::cout << "String: " << std::get< std::string > (value) << '\n';
168183 value = 42; // Value holds an int.
169184 std::cout << "Integer: " << std::get<int >(value) << '\n';
@@ -191,10 +206,10 @@ But we already saw that there is this function `std::visit` that we can use to m
191206#include < variant>
192207
193208struct Printer {
194- void operator(int value) const {
209+ void operator()( int value) const {
195210 std::cout << "Integer: " << value << '\n';
196211 }
197- void operator(std::string value) const {
212+ void operator()(const std::string& value) const {
198213 std::cout << "String: " << value << '\n';
199214 }
200215};
@@ -448,8 +463,9 @@ For this purpose there is a type `std::monostate` in the standard library. This
448463
449464<!--
450465` CPP_SETUP_START `
466+ #include <variant >
451467using SomeType = int;
452- using someOtherType = double;
468+ using SomeOtherType = double;
453469$PLACEHOLDER
454470` CPP_SETUP_END `
455471` CPP_COPY_SNIPPET ` variant_monostate/main.cpp
0 commit comments