@@ -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