├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md └── src ├── chapter_01 ├── CMakeLists.txt └── main.cpp ├── chapter_02 ├── CMakeLists.txt ├── main.cpp ├── source1.cpp ├── source2.cpp └── wrapper.h ├── chapter_03 ├── CMakeLists.txt └── main.cpp ├── chapter_04 ├── CMakeLists.txt └── main.cpp ├── chapter_05 ├── CMakeLists.txt └── main.cpp ├── chapter_06 ├── CMakeLists.txt └── main.cpp ├── chapter_07 ├── CMakeLists.txt └── main.cpp ├── chapter_08 ├── CMakeLists.txt └── main.cpp └── chapter_09 ├── CMakeLists.txt └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | 352 | # ignore build folder 353 | build/ 354 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(templatesbook) 3 | 4 | 5 | if(MSVC) 6 | message(status "Setting MSVC flags") 7 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHc /Zc:__cplusplus /std:c++latest") 8 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 9 | else() 10 | message(status "Setting GCC/Clang flags") 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a -fexceptions -g -Wall") 12 | endif() 13 | 14 | add_subdirectory(src/chapter_01) 15 | add_subdirectory(src/chapter_02) 16 | add_subdirectory(src/chapter_03) 17 | add_subdirectory(src/chapter_04) 18 | add_subdirectory(src/chapter_05) 19 | add_subdirectory(src/chapter_06) 20 | add_subdirectory(src/chapter_07) 21 | add_subdirectory(src/chapter_08) 22 | add_subdirectory(src/chapter_09) 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Template Metaprogramming with C++ 2 | 3 | Template Metaprogramming with C++ 4 | 5 | This is the code repository for [Template Metaprogramming with C++ ](https://www.amazon.com/Template-Metaprogramming-everything-templates-metaprogramming/dp/1803243457?utm_source=github&utm_medium=repository&utm_campaign=9781801076012), published by Packt. 6 | 7 | **Learn everything about C++ templates and unlock the power of template metaprogramming** 8 | 9 | ## What is this book about? 10 | Templates are a key feature of the C++ language that enable us to reuse source code, write more efficient code, and create generic libraries that can be used in many applications. Yet, they are often complex and hard to understand. This book will help you in understanding and writing templates from their simplest forms to the latest C++20 features. 11 | 12 | This book covers the following exciting features: 13 | * Understand the syntax for all types of templates 14 | * Discover how specialization and instantiation works 15 | * Get to grips with template argument deduction and forwarding references 16 | * Write variadic templates with ease 17 | * Become familiar with type traits and conditional compilation 18 | * Restrict template arguments in C++20 with constraints and concepts 19 | * Implement patterns such as CRTP, mixins, and tag dispatching 20 | 21 | If you feel this book is for you, get your [copy](https://www.amazon.com/dp/1803243457) today! 22 | 23 | https://www.packtpub.com/ 25 | 26 | ## Errata 27 | 28 | * Page 258: The line of code ``return value--;`` must be read as ``return value-1;`` or ``return --value;`` 29 | 30 | ## Instructions and Navigations 31 | All of the code is organized into folders. For example, Chapter02. 32 | 33 | The code will look like the following: 34 | ``` 35 | template 36 | struct parser : base_parser 37 | { 38 | void parse() 39 | { 40 | this->init(); // OK 41 | std::cout << "parse\n"; 42 | } 43 | }; 44 | ``` 45 | ## Structure 46 | 47 | The source code for the book is organized per chapters. Each chapter has its own subfolder in the `src` folder. These subfolders are called `chapter_01`, `chapter_02`, etc. For most chapters, the code is found in a single source file, `main.cpp`. This file is organized in multiple namespaces, such as `n101`, `n102`, `n103` etc. for the first chapter, `n201`, `n202`, `n203` etc. for the second chapter and so on. 48 | 49 | ## Supported compilers 50 | 51 | All the code provided in the book is cross-platform. You can use any of the major compilers, MSVC, Clang, or GCC to compile the sources. 52 | 53 | You can also run snippets of code using compilers available online: 54 | 55 | - [Compiler Explorer](https://godbolt.org/) 56 | - [Wandbox](https://wandbox.org/) 57 | - [C++ Insights](https://cppinsights.io/) 58 | 59 | ## How to build 60 | 61 | You must have CMake to build the code. 62 | 63 | ### Example for creating a Visual Studio solution 64 | 65 | Run the following commands to create a solution for Visual Studio 2019: 66 | 67 | ``` 68 | mkdir build 69 | cd build 70 | cmake -G "Visual Studio 16 2019" -A x64 .. 71 | ``` 72 | 73 | Run the following commands to create a solution for Visual Studio 2022: 74 | 75 | ``` 76 | mkdir build 77 | cd build 78 | cmake -G "Visual Studio 17 2022" -A x64 .. 79 | ``` 80 | 81 | **Following is what you need for this book:** 82 | This book is for beginner-to-intermediate C++ developers who want to learn about template metaprogramming as well as advanced C++ developers looking to get up to speed with the new C++20 features related to templates and the the various idioms and patterns. Basic C++ coding experience is necessary to get started with this book. 83 | 84 | We also provide a PDF file that has color images of the screenshots/diagrams used in this book. [Click here to download it](https://packt.link/Un8j5). 85 | 86 | ### Related products 87 | * C++20 STL Cookbook [[Packt]](https://www.packtpub.com/product/c-20-stl-cookbook/9781803248714?utm_source=github&utm_medium=repository&utm_campaign=9781803248714) [[Amazon]](https://www.amazon.com/dp/1803248718) 88 | 89 | * CMake Best Practices [[Packt]](https://www.packtpub.com/product/cmake-best-practices/9781803239729?utm_source=github&utm_medium=repository&utm_campaign=9781803239729) [[Amazon]](https://www.amazon.com/dp/1803239727) 90 | 91 | ## Get to Know the Author 92 | **Marius Bancila** 93 | is a software engineer with two decades of experience in developing solutions for line of business applications and more. He is the author of Modern C++ Programming Cookbook and The Modern C++ Challenge. He works as a software architect and is focused on Microsoft technologies, mainly developing desktop applications with C++ and C#. He is passionate about sharing his technical expertise with others and, for that reason, he has been recognized as a Microsoft MVP for C++ and later developer technologies since 2006. Marius lives in Romania and is active in various online communities. 94 | ### Download a free PDF 95 | 96 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
97 |

https://packt.link/free-ebook/9781803243450

98 | -------------------------------------------------------------------------------- /src/chapter_01/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB headers *.h) 2 | add_executable(chapter_01 main.cpp ${headers}) -------------------------------------------------------------------------------- /src/chapter_01/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace n101 4 | { 5 | int max(int const a, int const b) 6 | { 7 | return a > b ? a : b; 8 | } 9 | 10 | double max(double const a, double const b) 11 | { 12 | return a > b ? a : b; 13 | } 14 | 15 | using swap_fn = void(*)(void*, int const, int const); 16 | using compare_fn = bool(*)(void*, int const, int const); 17 | 18 | int partition(void* arr, int const low, int const high, 19 | compare_fn fcomp, swap_fn fswap) 20 | { 21 | int i = low - 1; 22 | 23 | for (int j = low; j <= high - 1; j++) 24 | { 25 | if (fcomp(arr, j, high)) 26 | { 27 | i++; 28 | fswap(arr, i, j); 29 | } 30 | } 31 | 32 | fswap(arr, i + 1, high); 33 | 34 | return i + 1; 35 | } 36 | 37 | void quicksort(void* arr, int const low, int const high, 38 | compare_fn fcomp, swap_fn fswap) 39 | { 40 | if (low < high) 41 | { 42 | int const pi = partition(arr, low, high, fcomp, fswap); 43 | quicksort(arr, low, pi - 1, fcomp, fswap); 44 | quicksort(arr, pi + 1, high, fcomp, fswap); 45 | } 46 | } 47 | 48 | void swap_int(void* arr, int const i, int const j) 49 | { 50 | int* iarr = (int*)arr; 51 | int t = iarr[i]; 52 | iarr[i] = iarr[j]; 53 | iarr[j] = t; 54 | } 55 | 56 | bool less_int(void* arr, int const i, int const j) 57 | { 58 | int* iarr = (int*)arr; 59 | return iarr[i] <= iarr[j]; 60 | } 61 | 62 | struct int_vector 63 | { 64 | int_vector(); 65 | 66 | size_t size() const; 67 | size_t capacity() const; 68 | bool empty() const; 69 | 70 | void clear(); 71 | void resize(size_t const size); 72 | 73 | void push_back(int value); 74 | void pop_back(); 75 | 76 | int at(size_t const index) const; 77 | int operator[](size_t const index) const; 78 | private: 79 | int* data_; 80 | size_t size_; 81 | size_t capacity_; 82 | }; 83 | 84 | constexpr char NewLine = '\n'; 85 | constexpr wchar_t NewLineW = L'\n'; 86 | constexpr char8_t NewLineU8 = u8'\n'; 87 | constexpr char16_t NewLineU16 = u'\n'; 88 | constexpr char32_t NewLineU32 = U'\n'; 89 | } 90 | 91 | namespace n102 92 | { 93 | template 94 | T max(T const a, T const b) 95 | { 96 | return a > b ? a : b; 97 | } 98 | 99 | struct foo {}; 100 | 101 | template 102 | void swap(T* a, T* b) 103 | { 104 | T t = *a; 105 | *a = *b; 106 | *b = t; 107 | } 108 | 109 | template 110 | int partition(T arr[], int const low, int const high) 111 | { 112 | T pivot = arr[high]; 113 | int i = (low - 1); 114 | 115 | for (int j = low; j <= high - 1; j++) 116 | { 117 | if (arr[j] < pivot) 118 | { 119 | i++; 120 | swap(&arr[i], &arr[j]); 121 | } 122 | } 123 | 124 | swap(&arr[i + 1], &arr[high]); 125 | 126 | return i + 1; 127 | } 128 | 129 | template 130 | void quicksort(T arr[], int const low, int const high) 131 | { 132 | if (low < high) 133 | { 134 | int const pi = partition(arr, low, high); 135 | quicksort(arr, low, pi - 1); 136 | quicksort(arr, pi + 1, high); 137 | } 138 | } 139 | 140 | template 141 | struct vector 142 | { 143 | vector(); 144 | 145 | size_t size() const; 146 | size_t capacity() const; 147 | bool empty() const; 148 | 149 | void clear(); 150 | void resize(size_t const size); 151 | 152 | void push_back(T value); 153 | void pop_back(); 154 | 155 | T at(size_t const index) const; 156 | T operator[](size_t const index) const; 157 | private: 158 | T* data_; 159 | size_t size_; 160 | size_t capacity_; 161 | }; 162 | 163 | template 164 | constexpr T NewLine = T('\n'); 165 | } 166 | 167 | int main() 168 | { 169 | { 170 | using namespace n101; 171 | 172 | int arr[] = { 13, 1, 8, 3, 5, 2, 1 }; 173 | int n = sizeof(arr) / sizeof(arr[0]); 174 | quicksort(arr, 0, n - 1, less_int, swap_int); 175 | } 176 | 177 | { 178 | using namespace n102; 179 | 180 | max(1, 2); // OK, compares ints 181 | max(1.0, 2.0); // OK, compares doubles 182 | 183 | //foo f1, f2; 184 | //max(f1, f2); // Error, operator> not overloaded for foo 185 | 186 | max(1, 2); 187 | max(1.0, 2.0); 188 | //max(f1, f2); 189 | } 190 | 191 | { 192 | using namespace n102; 193 | 194 | int arr[] = { 13, 1, 8, 3, 5, 2, 1 }; 195 | int n = sizeof(arr) / sizeof(arr[0]); 196 | quicksort(arr, 0, n - 1); 197 | } 198 | 199 | { 200 | using namespace n102; 201 | 202 | std::wstring test = L"demo"; 203 | test += NewLine; 204 | std::wcout << test; 205 | } 206 | } -------------------------------------------------------------------------------- /src/chapter_02/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB headers *.h) 2 | add_executable(chapter_02 source1.cpp source2.cpp main.cpp ${headers}) -------------------------------------------------------------------------------- /src/chapter_02/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "wrapper.h" 14 | 15 | 16 | 17 | 18 | namespace n201 19 | { 20 | template 21 | T add(T const a, T const b) 22 | { 23 | return a + b; 24 | } 25 | 26 | class foo 27 | { 28 | int value; 29 | public: 30 | explicit foo(int const i) :value(i) 31 | { 32 | } 33 | 34 | explicit operator int() const { return value; } 35 | }; 36 | 37 | foo operator+(foo const a, foo const b) 38 | { 39 | return foo((int)a + (int)b); 40 | } 41 | 42 | template 43 | int count_if(Input start, Input end, Predicate p) 44 | { 45 | int total = 0; 46 | for (Input i = start; i != end; i++) 47 | { 48 | if (p(*i)) 49 | total++; 50 | } 51 | return total; 52 | } 53 | } 54 | 55 | namespace n202 56 | { 57 | template 58 | class wrapper 59 | { 60 | public: 61 | wrapper(T const v):value(v) 62 | { } 63 | 64 | T const& get() const { return value; } 65 | private: 66 | T value; 67 | }; 68 | } 69 | 70 | namespace n203 71 | { 72 | template 73 | class wrapper; 74 | 75 | void use_wrapper(wrapper* ptr); 76 | } 77 | 78 | namespace n203 79 | { 80 | template 81 | class wrapper 82 | { 83 | public: 84 | wrapper(T const v) :value(v) 85 | { 86 | } 87 | 88 | T const& get() const { return value; } 89 | private: 90 | T value; 91 | }; 92 | 93 | void use_wrapper(wrapper* ptr) 94 | { 95 | std::cout << ptr->get() << '\n'; 96 | } 97 | } 98 | 99 | namespace n204 100 | { 101 | template 102 | class composition 103 | { 104 | public: 105 | T add(T const a, T const b) 106 | { 107 | return a + b; 108 | } 109 | }; 110 | } 111 | 112 | namespace n205 113 | { 114 | class composition 115 | { 116 | public: 117 | template 118 | T add(T const a, T const b) 119 | { 120 | return a + b; 121 | } 122 | }; 123 | } 124 | 125 | namespace n206 126 | { 127 | template 128 | class wrapper 129 | { 130 | public: 131 | wrapper(T const v) :value(v) 132 | { 133 | } 134 | 135 | T const& get() const { return value; } 136 | 137 | template 138 | U as() const 139 | { 140 | return static_cast(value); 141 | } 142 | private: 143 | T value; 144 | }; 145 | } 146 | 147 | namespace n207 148 | { 149 | template 150 | class wrapper1 { /* ... */ }; 151 | 152 | template 153 | class wrapper2 { /* ... */ }; 154 | 155 | template 156 | class wrapper3; 157 | 158 | template 159 | class wrapper4; 160 | 161 | template 162 | class wrapper5 { /* ... */ }; 163 | 164 | template 165 | concept WrappableType = std::is_trivial_v; 166 | 167 | template 168 | class wrapper6 { /* ... */ }; 169 | 170 | template 171 | class wrapper7 { /* ... */ }; 172 | 173 | template 174 | class wrapper8 { /* ... */ }; 175 | } 176 | 177 | namespace n208 178 | { 179 | template 180 | class foo1 { /*...*/ }; 181 | 182 | template 183 | class foo2 { /*...*/ }; 184 | 185 | template 186 | class foo3 { /*...*/ }; 187 | } 188 | 189 | namespace n209 190 | { 191 | template 192 | class buffer 193 | { 194 | T data_[S]; 195 | public: 196 | constexpr T const * data() const { return data_; } 197 | 198 | constexpr T& operator[](size_t const index) 199 | { 200 | return data_[index]; 201 | } 202 | 203 | constexpr T const & operator[](size_t const index) const 204 | { 205 | return data_[index]; 206 | } 207 | }; 208 | 209 | template 210 | buffer make_buffer() 211 | { 212 | return {}; 213 | } 214 | } 215 | 216 | namespace n210 217 | { 218 | struct device 219 | { 220 | virtual void output() = 0; 221 | virtual ~device() {} 222 | }; 223 | 224 | template 225 | struct smart_device : device 226 | { 227 | smart_device(Command* command) : cmd(command) {} 228 | 229 | void output() override 230 | { 231 | (cmd->*action)(); 232 | } 233 | private: 234 | Command* cmd; 235 | }; 236 | 237 | struct hello_command 238 | { 239 | void say_hello_in_english() 240 | { 241 | std::cout << "Hello, world!\n"; 242 | } 243 | 244 | void say_hello_in_spanish() 245 | { 246 | std::cout << "Hola mundo!\n"; 247 | } 248 | }; 249 | } 250 | 251 | namespace n211 252 | { 253 | struct device 254 | { 255 | virtual void output() = 0; 256 | virtual ~device() {} 257 | }; 258 | 259 | template 260 | struct smart_device : device 261 | { 262 | smart_device(Command& command) : cmd(command) {} 263 | 264 | void output() override 265 | { 266 | (cmd.*action)(); 267 | } 268 | private: 269 | Command& cmd; 270 | }; 271 | 272 | struct hello_command 273 | { 274 | void say_hello_in_english() 275 | { 276 | std::cout << "Hello, world!\n"; 277 | } 278 | 279 | void say_hello_in_spanish() 280 | { 281 | std::cout << "Hola mundo!\n"; 282 | } 283 | }; 284 | } 285 | 286 | namespace n212 287 | { 288 | struct device 289 | { 290 | virtual void output() = 0; 291 | virtual ~device() {} 292 | }; 293 | 294 | template 295 | struct smart_device : device 296 | { 297 | void output() override 298 | { 299 | (*action)(); 300 | } 301 | }; 302 | 303 | void say_hello_in_english() 304 | { 305 | std::cout << "Hello, world!\n"; 306 | } 307 | 308 | void say_hello_in_spanish() 309 | { 310 | std::cout << "Hola mundo!\n"; 311 | } 312 | } 313 | 314 | namespace n213 315 | { 316 | template 317 | struct foo 318 | { 319 | }; 320 | } 321 | 322 | namespace n214 323 | { 324 | template 325 | struct string_literal 326 | { 327 | constexpr string_literal(const char(&str)[N]) 328 | { 329 | std::copy_n(str, N, value); 330 | } 331 | 332 | char value[N]; 333 | }; 334 | 335 | template 336 | struct foo 337 | { 338 | }; 339 | } 340 | 341 | namespace n215 342 | { 343 | template 344 | struct foo 345 | { /* ... */ }; 346 | } 347 | 348 | namespace n216 349 | { 350 | template 351 | class simple_wrapper 352 | { 353 | public: 354 | T value; 355 | }; 356 | 357 | template 358 | class fancy_wrapper 359 | { 360 | public: 361 | fancy_wrapper(T const v) :value(v) 362 | { 363 | } 364 | 365 | T const& get() const { return value; } 366 | 367 | template 368 | U as() const 369 | { 370 | return static_cast(value); 371 | } 372 | private: 373 | T value; 374 | }; 375 | 376 | template typename W = fancy_wrapper> 377 | class wrapping_pair 378 | { 379 | public: 380 | wrapping_pair(T const a, U const b) : 381 | item1(a), item2(b) 382 | { 383 | } 384 | 385 | W item1; 386 | W item2; 387 | }; 388 | } 389 | 390 | namespace n217 391 | { 392 | template 393 | class foo { /*...*/ }; 394 | 395 | template 396 | class bar { /*...*/ }; 397 | } 398 | 399 | namespace n218 400 | { 401 | // template 402 | // class bar { }; 403 | 404 | template 405 | void func() {} 406 | } 407 | 408 | namespace n219 409 | { 410 | template 411 | struct foo; 412 | 413 | template 414 | struct foo; 415 | 416 | template 417 | struct foo 418 | { 419 | T a; 420 | U b; 421 | }; 422 | } 423 | 424 | namespace n220 425 | { 426 | template 427 | struct foo; 428 | 429 | //template // error 430 | //struct foo {}; 431 | } 432 | 433 | namespace n221 434 | { 435 | template 436 | struct foo 437 | { 438 | protected: 439 | using value_type = T; 440 | }; 441 | 442 | template 443 | struct bar 444 | { 445 | using value_type = U; 446 | }; 447 | } 448 | 449 | namespace n222 450 | { 451 | template 452 | struct foo 453 | { 454 | void f() {} 455 | void g() { int a = "42"; } 456 | }; 457 | } 458 | 459 | namespace n223 460 | { 461 | template 462 | struct foo 463 | { 464 | void f() {} 465 | void g() {} 466 | }; 467 | } 468 | 469 | namespace n224 470 | { 471 | template 472 | struct control 473 | { 474 | }; 475 | 476 | template 477 | struct button : public control 478 | { 479 | }; 480 | 481 | void show(button* ptr) 482 | { 483 | control* c = ptr; 484 | } 485 | } 486 | 487 | namespace n225 488 | { 489 | template 490 | struct foo 491 | { 492 | static T data; 493 | }; 494 | 495 | template T foo::data = 0; 496 | } 497 | 498 | namespace n226 499 | { 500 | template 501 | struct wrapper 502 | { 503 | T value; 504 | }; 505 | 506 | template struct wrapper; // [1] 507 | } 508 | 509 | template struct n226::wrapper; // [2] 510 | 511 | namespace n226 512 | { 513 | template 514 | T add(T const a, T const b) 515 | { 516 | return a + b; 517 | } 518 | 519 | template int add(int, int); // [1] 520 | } 521 | 522 | template int n226::add(int, int); // [2] 523 | 524 | namespace n227 525 | { 526 | template 527 | class foo 528 | { 529 | struct bar {}; 530 | 531 | T f(bar const arg) 532 | { 533 | return {}; 534 | } 535 | }; 536 | 537 | template int foo::f(foo::bar); 538 | } 539 | 540 | namespace n228 541 | { 542 | template 543 | struct is_floating_point 544 | { 545 | constexpr static bool value = false; 546 | }; 547 | 548 | template <> 549 | struct is_floating_point 550 | { 551 | constexpr static bool value = true; 552 | }; 553 | 554 | template <> 555 | struct is_floating_point 556 | { 557 | constexpr static bool value = true; 558 | }; 559 | 560 | template <> 561 | struct is_floating_point 562 | { 563 | constexpr static bool value = true; 564 | }; 565 | 566 | template 567 | inline constexpr bool is_floating_point_v = is_floating_point::value; 568 | } 569 | 570 | namespace n229 571 | { 572 | template 573 | struct is_floating_point; 574 | 575 | template <> 576 | struct is_floating_point 577 | { 578 | constexpr static bool value = true; 579 | }; 580 | 581 | template 582 | struct is_floating_point 583 | { 584 | constexpr static bool value = false; 585 | }; 586 | } 587 | 588 | namespace n230 589 | { 590 | template 591 | struct foo {}; // primary template 592 | 593 | template <> 594 | struct foo; // explicit specialization declaration 595 | } 596 | 597 | namespace n231 598 | { 599 | template 600 | struct foo {}; 601 | 602 | template 603 | void func(foo) 604 | { 605 | std::cout << "primary template\n"; 606 | } 607 | 608 | template<> 609 | void func(foo) 610 | { 611 | std::cout << "int specialization\n"; 612 | } 613 | } 614 | 615 | namespace n232 616 | { 617 | template 618 | void func(T a) 619 | { 620 | std::cout << "primary template\n"; 621 | } 622 | 623 | template <> 624 | void func(int a /*= 0*/) // error: default argument 625 | { 626 | std::cout << "int specialization\n"; 627 | } 628 | } 629 | 630 | namespace n233 631 | { 632 | template 633 | struct foo 634 | { 635 | static T value; 636 | }; 637 | 638 | template T foo::value = 0; 639 | 640 | template <> int foo::value = 42; 641 | } 642 | 643 | namespace n234 644 | { 645 | template 646 | void func(T a, U b) 647 | { 648 | std::cout << "primary template\n"; 649 | } 650 | 651 | template <> 652 | void func(int a, int b) 653 | { 654 | std::cout << "int-int specialization\n"; 655 | } 656 | 657 | template <> 658 | void func(int a, double b) 659 | { 660 | std::cout << "int-double specialization\n"; 661 | } 662 | } 663 | 664 | namespace n235 665 | { 666 | template 667 | struct collection 668 | { 669 | void operator()() 670 | { 671 | std::cout << "primary template\n"; 672 | } 673 | }; 674 | 675 | template 676 | struct collection 677 | { 678 | void operator()() 679 | { 680 | std::cout << "partial specialization \n"; 681 | } 682 | }; 683 | 684 | template 685 | struct collection 686 | { 687 | void operator()() 688 | { 689 | std::cout << "partial specialization \n"; 690 | } 691 | }; 692 | 693 | template 694 | struct collection 695 | { 696 | void operator()() 697 | { 698 | std::cout << "partial specialization \n"; 699 | } 700 | }; 701 | } 702 | 703 | namespace n236 704 | { 705 | template 706 | struct foo {}; 707 | 708 | template 709 | struct foo {}; 710 | 711 | //template 712 | //struct foo {}; // error 713 | } 714 | 715 | namespace n237 716 | { 717 | template 718 | std::ostream& pretty_print(std::ostream& os, std::array const& arr) 719 | { 720 | os << '['; 721 | if (S > 0) 722 | { 723 | size_t i = 0; 724 | for (; i < S - 1; ++i) 725 | os << arr[i] << ','; 726 | os << arr[S - 1]; 727 | } 728 | os << ']'; 729 | 730 | return os; 731 | } 732 | } 733 | 734 | namespace n238 735 | { 736 | template 737 | std::ostream& pretty_print(std::ostream& os, std::array const& arr) 738 | { 739 | os << '['; 740 | for (auto const& e : arr) 741 | os << e; 742 | os << ']'; 743 | 744 | return os; 745 | } 746 | } 747 | 748 | namespace n239 749 | { 750 | constexpr double PI = 3.1415926535897932385L; 751 | 752 | template 753 | T sphere_volume(T const r) 754 | { 755 | return static_cast(4 * PI * r * r * r / 3); 756 | } 757 | } 758 | 759 | namespace n240 760 | { 761 | template 762 | struct PI 763 | { 764 | static const T value; 765 | }; 766 | 767 | template 768 | const T PI::value = T(3.1415926535897932385L); 769 | 770 | template 771 | T sphere_volume(T const r) 772 | { 773 | return 4 * PI::value * r * r * r / 3; 774 | } 775 | } 776 | 777 | namespace n241 778 | { 779 | template 780 | constexpr T PI = T(3.1415926535897932385L); 781 | 782 | template 783 | T sphere_volume(T const r) 784 | { 785 | return 4 * PI * r * r * r / 3; 786 | } 787 | } 788 | 789 | namespace n242 790 | { 791 | struct math_constants 792 | { 793 | template 794 | static constexpr T PI = T(3.1415926535897932385L); 795 | }; 796 | 797 | template 798 | T sphere_volume(T const r) 799 | { 800 | return 4 * math_constants::PI *r * r * r / 3; 801 | } 802 | } 803 | 804 | namespace n243 805 | { 806 | struct math_constants 807 | { 808 | template 809 | static const T PI; 810 | }; 811 | 812 | template 813 | const T math_constants::PI = T(3.1415926535897932385L); 814 | 815 | template 816 | T sphere_volume(T const r) 817 | { 818 | return 4 * math_constants::PI *r * r * r / 3; 819 | } 820 | } 821 | 822 | namespace n244 823 | { 824 | template 825 | constexpr T SEPARATOR = '\n'; 826 | 827 | template<> 828 | constexpr wchar_t SEPARATOR = L'\n'; 829 | 830 | template 831 | std::basic_ostream& show_parts(std::basic_ostream& s, 832 | std::basic_string_view const& str) 833 | { 834 | using size_type = typename std::basic_string_view::size_type; 835 | size_type start = 0; 836 | size_type end; 837 | do 838 | { 839 | end = str.find(SEPARATOR, start); 840 | s << '[' << str.substr(start, end - start) << ']' << SEPARATOR; 841 | start = end+1; 842 | } while (end != std::string::npos); 843 | 844 | return s; 845 | } 846 | } 847 | 848 | namespace n245 849 | { 850 | template 851 | struct foo 852 | { 853 | typedef T value_type; 854 | }; 855 | } 856 | 857 | namespace n246 858 | { 859 | template 860 | struct foo 861 | { 862 | using value_type = T; 863 | }; 864 | } 865 | 866 | namespace n247 867 | { 868 | template 869 | using customer_addresses_t = std::map>; 870 | 871 | struct delivery_address_t {}; 872 | struct invoice_address_t {}; 873 | 874 | using customer_delivery_addresses_t = customer_addresses_t; 875 | using customer_invoice_addresses_t = customer_addresses_t; 876 | } 877 | 878 | namespace n247 879 | { 880 | template 881 | struct list 882 | { 883 | using type = std::vector; 884 | }; 885 | 886 | template 887 | struct list 888 | { 889 | using type = T; 890 | }; 891 | 892 | template 893 | using list_t = typename list::type; 894 | } 895 | 896 | namespace n248 897 | { 898 | 899 | } 900 | 901 | int main() 902 | { 903 | { 904 | using namespace n201; 905 | 906 | auto a1 = add(42, 21); 907 | auto a2 = add(42, 21); 908 | auto a3 = add<>(42, 21); 909 | 910 | auto b = add(42, 21); 911 | 912 | //auto d1 = add(41.0, 21); // error 913 | auto d2 = add(41.0, 21); 914 | 915 | auto f = add(foo(42), foo(41)); 916 | 917 | int arr[]{ 1,1,2,3,5,8,11 }; 918 | int odds = count_if(std::begin(arr), std::end(arr), 919 | [](int const n) { return n % 2 == 1; }); 920 | std::cout << odds << '\n'; 921 | } 922 | 923 | { 924 | using namespace n202; 925 | 926 | wrapper a(42); // wraps an int 927 | wrapper b(42); // wraps an int 928 | wrapper c(42); // wraps a short 929 | wrapper d(42.0); // wraps a double 930 | wrapper e("42"); // wraps a char const * 931 | } 932 | 933 | { 934 | using namespace n203; 935 | 936 | wrapper a(42); // wraps an int 937 | use_wrapper(&a); 938 | } 939 | 940 | { 941 | using namespace n204; 942 | 943 | composition c; 944 | c.add(41, 21); 945 | } 946 | 947 | { 948 | using namespace n205; 949 | 950 | composition c; 951 | c.add(41, 21); 952 | } 953 | 954 | { 955 | using namespace n206; 956 | 957 | wrapper a(42.0); 958 | auto d = a.get(); // double 959 | auto n = a.as(); // int 960 | } 961 | 962 | { 963 | using namespace n209; 964 | 965 | buffer b1; 966 | b1[0] = 42; 967 | std::cout << b1[0] << '\n'; 968 | 969 | auto b2 = make_buffer(); 970 | } 971 | 972 | { 973 | using namespace n209; 974 | 975 | buffer b1; 976 | buffer b2; 977 | 978 | std::cout << std::is_same_v, buffer> << '\n'; 979 | std::cout << std::is_same_v << '\n'; 980 | 981 | static_assert(std::is_same_v); 982 | 983 | buffer b3; 984 | static_assert(!std::is_same_v); 985 | } 986 | 987 | { 988 | using namespace n210; 989 | 990 | hello_command cmd; 991 | 992 | auto w1 = std::make_unique>(&cmd); 993 | w1->output(); 994 | 995 | auto w2 = std::make_unique>(&cmd); 996 | w2->output(); 997 | } 998 | 999 | { 1000 | using namespace n211; 1001 | 1002 | hello_command cmd; 1003 | 1004 | auto w1 = std::make_unique>(cmd); 1005 | w1->output(); 1006 | 1007 | auto w2 = std::make_unique>(cmd); 1008 | w2->output(); 1009 | } 1010 | 1011 | { 1012 | using namespace n212; 1013 | 1014 | auto w1 = std::make_unique>(); 1015 | w1->output(); 1016 | 1017 | auto w2 = std::make_unique>(); 1018 | w2->output(); 1019 | 1020 | static_assert(!std::is_same_v); 1021 | } 1022 | 1023 | { 1024 | using namespace n212; 1025 | 1026 | std::unique_ptr w1 = std::make_unique>(); 1027 | w1->output(); 1028 | 1029 | std::unique_ptr w2 = std::make_unique>(); 1030 | w2->output(); 1031 | 1032 | static_assert(std::is_same_v); 1033 | } 1034 | 1035 | { 1036 | using namespace n213; 1037 | [[maybe_unused]] foo<42> f1; // foo 1038 | [[maybe_unused]] foo<42.0> f2; // foo 1039 | //foo<"42"> f3; // error 1040 | } 1041 | 1042 | { 1043 | using namespace n214; 1044 | [[maybe_unused]] foo<"42"> f; 1045 | } 1046 | 1047 | { 1048 | using namespace n215; 1049 | [[maybe_unused]] foo<42, 42.0, false, 'x'> f; 1050 | } 1051 | 1052 | { 1053 | using namespace n216; 1054 | wrapping_pair p1(42, 42.0); 1055 | std::cout << p1.item1.get() << ' ' 1056 | << p1.item2.get() << '\n'; 1057 | 1058 | wrapping_pair p2(42, 42.0); 1059 | std::cout << p2.item1.value << ' ' 1060 | << p2.item2.value << '\n'; 1061 | } 1062 | 1063 | { 1064 | using namespace n219; 1065 | foo f{ 42, 42.0 }; 1066 | } 1067 | 1068 | { 1069 | using namespace n221; 1070 | //bar> x; 1071 | } 1072 | 1073 | { 1074 | using namespace n222; 1075 | foo a; 1076 | a.f(); 1077 | //a.g(); 1078 | } 1079 | 1080 | { 1081 | using namespace n223; 1082 | 1083 | [[maybe_unused]] foo* p; 1084 | [[maybe_unused]] foo x; 1085 | [[maybe_unused]] foo* q; 1086 | } 1087 | 1088 | { 1089 | using namespace n223; 1090 | 1091 | [[maybe_unused]] foo* p; 1092 | foo x; 1093 | foo* q = nullptr; 1094 | 1095 | x.f(); 1096 | q->g(); 1097 | } 1098 | 1099 | { 1100 | using namespace n225; 1101 | 1102 | foo a; 1103 | foo b; 1104 | foo c; 1105 | 1106 | std::cout << a.data << '\n'; // 0 1107 | std::cout << b.data << '\n'; // 0 1108 | std::cout << c.data << '\n'; // 0 1109 | 1110 | b.data = 42; 1111 | std::cout << b.data << '\n'; // 42 1112 | std::cout << c.data << '\n'; // 42 1113 | } 1114 | 1115 | { 1116 | using namespace ext; 1117 | 1118 | wrapper a{ 0 }; 1119 | 1120 | std::cout << a.data << '\n'; 1121 | f(); 1122 | g(); 1123 | } 1124 | 1125 | { 1126 | using namespace n228; 1127 | 1128 | std::cout << is_floating_point::value << '\n'; 1129 | std::cout << is_floating_point::value << '\n'; 1130 | std::cout << is_floating_point::value << '\n'; 1131 | std::cout << is_floating_point::value << '\n'; 1132 | std::cout << is_floating_point::value << '\n'; 1133 | } 1134 | 1135 | { 1136 | using namespace n228; 1137 | 1138 | std::cout << is_floating_point_v << '\n'; 1139 | std::cout << is_floating_point_v << '\n'; 1140 | std::cout << is_floating_point_v << '\n'; 1141 | std::cout << is_floating_point_v << '\n'; 1142 | std::cout << is_floating_point_v << '\n'; 1143 | } 1144 | 1145 | { 1146 | using namespace n229; 1147 | 1148 | std::cout << is_floating_point::value << '\n'; 1149 | std::cout << is_floating_point::value << '\n'; 1150 | } 1151 | 1152 | { 1153 | using namespace n230; 1154 | 1155 | [[maybe_unused]] foo a; // OK 1156 | [[maybe_unused]] foo* b; // OK 1157 | //foo c; // error, foo incomplete type 1158 | } 1159 | 1160 | { 1161 | using namespace n231; 1162 | 1163 | func(foo{}); 1164 | func(foo{}); 1165 | } 1166 | 1167 | { 1168 | using namespace n232; 1169 | 1170 | func(42.0); 1171 | func(42); 1172 | } 1173 | 1174 | { 1175 | using namespace n233; 1176 | 1177 | foo a, b; 1178 | std::cout << a.value << '\n'; 1179 | std::cout << b.value << '\n'; 1180 | 1181 | foo c; 1182 | std::cout << c.value << '\n'; 1183 | 1184 | a.value = 100; 1185 | std::cout << a.value << '\n'; 1186 | std::cout << b.value << '\n'; 1187 | std::cout << c.value << '\n'; 1188 | } 1189 | 1190 | { 1191 | using namespace n234; 1192 | 1193 | func(1, 2); 1194 | func(1, 2.0); 1195 | func(1.0, 2.0); 1196 | } 1197 | 1198 | { 1199 | using namespace n235; 1200 | 1201 | collection{}(); // primary template 1202 | collection{}(); // partial specialization 1203 | collection{}(); // partial specialization 1204 | collection{}(); // partial specialization 1205 | 1206 | //collection{}(); // error: collection or collection 1207 | //collection{}(); // error: collection or collection 1208 | } 1209 | 1210 | { 1211 | using namespace n237; 1212 | 1213 | std::array arr {1, 1, 2, 3, 5, 8, 13, 21}; 1214 | pretty_print(std::cout, arr); 1215 | 1216 | std::array str; 1217 | std::strcpy(str.data(), "template"); 1218 | pretty_print(std::cout, str); 1219 | } 1220 | 1221 | { 1222 | using namespace n238; 1223 | 1224 | std::array str; 1225 | std::strcpy(str.data(), "template"); 1226 | pretty_print(std::cout, str); 1227 | } 1228 | 1229 | { 1230 | using namespace n239; 1231 | 1232 | float v1 = sphere_volume(42.0f); 1233 | double v2 = sphere_volume(42.0); 1234 | } 1235 | 1236 | { 1237 | using namespace n240; 1238 | 1239 | float v1 = sphere_volume(42.0f); 1240 | double v2 = sphere_volume(42.0); 1241 | } 1242 | 1243 | { 1244 | using namespace n241; 1245 | 1246 | float v1 = sphere_volume(42.0f); 1247 | double v2 = sphere_volume(42.0); 1248 | } 1249 | 1250 | { 1251 | using namespace n242; 1252 | 1253 | float v1 = sphere_volume(42.0f); 1254 | double v2 = sphere_volume(42.0); 1255 | } 1256 | 1257 | { 1258 | using namespace n244; 1259 | show_parts(std::cout, "one\ntwo\nthree"); 1260 | show_parts(std::wcout, L"one line"); 1261 | } 1262 | 1263 | { 1264 | typedef int index_t; 1265 | typedef std::vector> NameValueList; 1266 | typedef int (*fn_ptr)(int, char); 1267 | 1268 | } 1269 | 1270 | { 1271 | using index_t = int; 1272 | using NameValueList = std::vector>; 1273 | using fn_ptr = int(int, char); 1274 | } 1275 | 1276 | { 1277 | using namespace n247; 1278 | static_assert(std::is_same_v, int>); 1279 | static_assert(std::is_same_v, std::vector>); 1280 | } 1281 | 1282 | { 1283 | int arr[] = { 1,6,3,8,4,2,9 }; 1284 | std::sort( 1285 | std::begin(arr), std::end(arr), 1286 | [](int const a, int const b) {return a > b; }); 1287 | 1288 | int pivot = 5; 1289 | auto count = std::count_if( 1290 | std::begin(arr), std::end(arr), 1291 | [pivot](int const a) {return a > pivot; }); 1292 | 1293 | std::cout << count << '\n'; 1294 | } 1295 | 1296 | { 1297 | auto l1 = [](int a) {return a + a; }; // C++11, regular lambda 1298 | auto l2 = [](auto a) {return a + a; }; // C++14, generic lambda 1299 | auto l3 = [](T a) { return a + a; };// C++20, template lambda 1300 | 1301 | auto v1 = l1(42); // OK 1302 | auto v2 = l1(42.0); // warning 1303 | //auto v3 = l1(std::string{ "42" }); // error 1304 | 1305 | auto v5 = l2(42); // OK 1306 | auto v6 = l2(42.0); // OK 1307 | auto v7 = l2(std::string{"42"}); // OK 1308 | 1309 | auto v8 = l3(42); // OK 1310 | auto v9 = l3(42.0); // OK 1311 | auto v10 = l3(std::string{ "42" }); // OK 1312 | } 1313 | 1314 | { 1315 | auto l1 = [](int a, int b) {return a + b; }; 1316 | auto l2 = [](auto a, auto b) {return a + b; }; 1317 | auto l3 = [](T a, U b) { return a + b; }; 1318 | auto l4 = [](auto a, decltype(a) b) {return a + b; }; 1319 | 1320 | auto v1 = l1(42, 1); // OK 1321 | auto v2 = l1(42.0, 1.0); // warning 1322 | //auto v3 = l1(std::string{ "42" }, '1'); // error 1323 | 1324 | auto v4 = l2(42, 1); // OK 1325 | auto v5 = l2(42.0, 1); // OK 1326 | auto v6 = l2(std::string{ "42" }, '1'); // OK 1327 | auto v7 = l2(std::string{ "42" }, std::string{ "1" }); // OK 1328 | 1329 | auto v8 = l3(42, 1); // OK 1330 | auto v9 = l3(42.0, 1); // OK 1331 | auto v10 = l3(std::string{ "42" }, '1'); // OK 1332 | auto v11 = l3(std::string{ "42" }, std::string{ "42" }); // OK 1333 | 1334 | auto v12 = l4(42.0, 1); // OK 1335 | auto v13 = l4(42, 1.0); // warning 1336 | //auto v14 = l4(std::string{ "42" }, '1'); // error 1337 | } 1338 | 1339 | { 1340 | auto l = [](std::array const& arr) { return std::accumulate(arr.begin(), arr.end(), static_cast(0)); }; 1341 | 1342 | //auto v1 = l(1); // error 1343 | auto v2 = l(std::array{1, 2, 3}); 1344 | } 1345 | 1346 | { 1347 | auto l = [](T a, T b) { return a + b; }; 1348 | 1349 | auto v1 = l(42, 1); // OK 1350 | //auto v2 = l(42.0, 1); // error 1351 | 1352 | auto v4 = l(42.0, 1.0); // OK 1353 | //auto v5 = l(42, false); // error 1354 | 1355 | auto v6 = l(std::string{ "42" }, std::string{ "1" }); // OK 1356 | //auto v6 = l(std::string{ "42" }, '1'); // error 1357 | } 1358 | 1359 | { 1360 | std::function factorial; 1361 | factorial = [&factorial](int const n) { 1362 | if (n < 2) return 1; 1363 | else return n * factorial(n - 1); 1364 | }; 1365 | 1366 | std::cout << factorial(5) << '\n'; 1367 | } 1368 | 1369 | { 1370 | auto factorial = [](auto f, int const n) { 1371 | if (n < 2) return 1; 1372 | else return n * f(f, n - 1); 1373 | }; 1374 | 1375 | std::cout << factorial(factorial, 5) << '\n'; 1376 | } 1377 | } 1378 | 1379 | -------------------------------------------------------------------------------- /src/chapter_02/source1.cpp: -------------------------------------------------------------------------------- 1 | #include "wrapper.h" 2 | #include 3 | 4 | namespace ext 5 | { 6 | template wrapper; 7 | 8 | void f() 9 | { 10 | ext::wrapper a{ 42 }; 11 | 12 | std::cout << a.data << '\n'; 13 | } 14 | } -------------------------------------------------------------------------------- /src/chapter_02/source2.cpp: -------------------------------------------------------------------------------- 1 | #include "wrapper.h" 2 | #include 3 | 4 | namespace ext 5 | { 6 | void g() 7 | { 8 | wrapper a{ 100 }; 9 | 10 | std::cout << a.data << '\n'; 11 | } 12 | } -------------------------------------------------------------------------------- /src/chapter_02/wrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace ext 4 | { 5 | template 6 | struct wrapper 7 | { 8 | T data; 9 | }; 10 | 11 | extern template wrapper; 12 | 13 | void f(); 14 | void g(); 15 | } -------------------------------------------------------------------------------- /src/chapter_03/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB headers *.h) 2 | add_executable(chapter_03 main.cpp ${headers}) -------------------------------------------------------------------------------- /src/chapter_03/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace n301 7 | { 8 | #include 9 | 10 | int min(int count, ...) 11 | { 12 | va_list args; 13 | va_start(args, count); 14 | 15 | int val = va_arg(args, int); 16 | for (int i = 1; i < count; i++) 17 | { 18 | int n = va_arg(args, int); 19 | if (n < val) 20 | val = n; 21 | } 22 | 23 | va_end(args); 24 | 25 | return val; 26 | } 27 | } 28 | 29 | namespace n302 30 | { 31 | #include 32 | 33 | template 34 | T min(int count, ...) 35 | { 36 | va_list args; 37 | va_start(args, count); 38 | 39 | T val = va_arg(args, T); 40 | for (int i = 1; i < count; i++) 41 | { 42 | T n = va_arg(args, T); 43 | if (n < val) 44 | val = n; 45 | } 46 | 47 | va_end(args); 48 | 49 | return val; 50 | } 51 | } 52 | 53 | namespace n303 54 | { 55 | template 56 | T min(T a, T b) 57 | { 58 | return a < b ? a : b; 59 | } 60 | 61 | template 62 | T min(T a, Args... args) 63 | { 64 | return min(a, min(args...)); 65 | } 66 | } 67 | 68 | namespace n304 69 | { 70 | int min(int a, int b) 71 | { 72 | return a < b ? a : b; 73 | } 74 | 75 | int min(int a, int b, int c) 76 | { 77 | return min(a, min(b, c)); 78 | } 79 | 80 | int min(int a, int b, int c, int d) 81 | { 82 | return min(a, min(b, min(c, d))); 83 | } 84 | 85 | int min(int a, int b, int c, int d, int e) 86 | { 87 | return min(a, min(b, min(c, min(d, e)))); 88 | } 89 | } 90 | 91 | namespace n305 92 | { 93 | template 94 | T min(T a, T b) 95 | { 96 | #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) 97 | std::cout << __PRETTY_FUNCTION__ << "\n"; 98 | #elif defined(_MSC_VER) 99 | std::cout << __FUNCSIG__ << "\n"; 100 | #endif 101 | return a < b ? a : b; 102 | } 103 | 104 | template 105 | T min(T a, Args... args) 106 | { 107 | #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) 108 | std::cout << __PRETTY_FUNCTION__ << "\n"; 109 | #elif defined(_MSC_VER) 110 | std::cout << __FUNCSIG__ << "\n"; 111 | #endif 112 | return min(a, min(args...)); 113 | } 114 | } 115 | 116 | namespace n306 117 | { 118 | template 119 | T sum(T a, Args... args) 120 | { 121 | if constexpr (sizeof...(args) == 0) 122 | return a; 123 | else 124 | return a + sum(args...); 125 | } 126 | } 127 | 128 | namespace n307 129 | { 130 | template 131 | T sum(T a) 132 | { 133 | return a; 134 | } 135 | 136 | template 137 | T sum(T a, Args... args) 138 | { 139 | return a + sum(args...); 140 | } 141 | } 142 | 143 | namespace n308 144 | { 145 | template 146 | constexpr auto get_type_sizes() 147 | { 148 | return std::array{sizeof(Ts)...}; 149 | } 150 | } 151 | 152 | namespace n309 153 | { 154 | template 155 | constexpr auto get_type_sizes() 156 | { 157 | return std::array { 158 | sizeof(T1), sizeof(T2), sizeof(T3), sizeof(T4) 159 | }; 160 | } 161 | } 162 | 163 | namespace n310 164 | { 165 | template 166 | constexpr auto multipacks(Ts... args1, Us... args2) 167 | { 168 | std::cout << sizeof...(args1) << ',' 169 | << sizeof...(args2) << '\n'; 170 | } 171 | } 172 | 173 | namespace n311 174 | { 175 | template 176 | constexpr auto multipacks(Ts... args1, Us... args2) 177 | { 178 | static_assert( 179 | sizeof...(args1) == sizeof...(args2), 180 | "Packs must be of equal sizes."); 181 | } 182 | } 183 | 184 | namespace n312 185 | { 186 | bool twice_as(int a, int b) 187 | { 188 | return a >= b*2; 189 | } 190 | 191 | double sum_and_div(int a, int b, double c) 192 | { 193 | return (a + b) / c; 194 | } 195 | 196 | template 197 | struct func_pair; 198 | 199 | template 200 | struct func_pair 201 | { 202 | std::function f; 203 | std::function g; 204 | }; 205 | } 206 | 207 | namespace n313 208 | { 209 | template 210 | struct tuple 211 | { 212 | tuple(T const& t, Ts const &... ts) 213 | : value(t), rest(ts...) 214 | { 215 | } 216 | 217 | constexpr int size() const { return 1 + rest.size(); } 218 | 219 | T value; 220 | tuple rest; 221 | }; 222 | 223 | template 224 | struct tuple 225 | { 226 | tuple(const T& t) 227 | : value(t) 228 | { 229 | } 230 | 231 | constexpr int size() const { return 1; } 232 | 233 | T value; 234 | }; 235 | 236 | template 237 | struct nth_type : nth_type 238 | { 239 | static_assert(N < sizeof...(Ts) + 1, "index out of bounds"); 240 | }; 241 | 242 | template 243 | struct nth_type<0, T, Ts...> 244 | { 245 | using value_type = T; 246 | }; 247 | 248 | template 249 | struct getter 250 | { 251 | template 252 | static typename nth_type::value_type& get(tuple& t) 253 | { 254 | return getter::get(t.rest); 255 | } 256 | }; 257 | 258 | template <> 259 | struct getter<0> 260 | { 261 | template 262 | static T& get(tuple& t) 263 | { 264 | return t.value; 265 | } 266 | }; 267 | 268 | template 269 | typename nth_type::value_type & get(tuple& t) 270 | { 271 | return getter::get(t); 272 | } 273 | } 274 | 275 | namespace n314 276 | { 277 | template 278 | int sum(T... args) 279 | { 280 | return (... + args); 281 | } 282 | 283 | template 284 | int sum_from_zero(T... args) 285 | { 286 | return (0 + ... + args); 287 | } 288 | } 289 | 290 | namespace n315 291 | { 292 | template 293 | int suml(T... args) 294 | { 295 | return (... + args); 296 | } 297 | 298 | template 299 | int sumr(T... args) 300 | { 301 | return (args + ...); 302 | } 303 | 304 | template 305 | void printl(T... args) 306 | { 307 | (..., (std::cout << args)) << '\n'; 308 | } 309 | 310 | template 311 | void printr(T... args) 312 | { 313 | ((std::cout << args), ...) << '\n'; 314 | } 315 | 316 | template 317 | void print(T... args) 318 | { 319 | (std::cout << ... << args) << '\n'; 320 | } 321 | 322 | template 323 | void push_back_many(std::vector& v, Args&&... args) 324 | { 325 | (v.push_back(args), ...); 326 | } 327 | } 328 | 329 | namespace n316 330 | { 331 | template 332 | constexpr int Sum = (... + R); 333 | 334 | template 335 | constexpr auto indexes = std::make_index_sequence<5>; 336 | } 337 | 338 | namespace n317 339 | { 340 | template 341 | struct foo 342 | { 343 | }; 344 | 345 | template 346 | using int_foo = foo; 347 | 348 | template 349 | struct integer_sequence 350 | { 351 | }; 352 | 353 | template 354 | using index_sequence = integer_sequence; 355 | 356 | template 357 | struct make_integer_sequence : make_integer_sequence {}; 358 | 359 | template 360 | struct make_integer_sequence : integer_sequence {}; 361 | 362 | template 363 | using make_index_sequence = make_integer_sequence; 364 | 365 | template 366 | using index_sequence_for = make_index_sequence; 367 | 368 | template 369 | auto select_tuple(Tuple&& tuple, index_sequence) 370 | { 371 | return std::make_tuple( 372 | std::get(std::forward(tuple))...); 373 | } 374 | } 375 | 376 | namespace n318 377 | { 378 | template 379 | struct outer 380 | { 381 | template 382 | struct inner {}; 383 | }; 384 | 385 | template 386 | struct tag 387 | { 388 | }; 389 | 390 | template 391 | void tagger() 392 | { 393 | [[maybe_unused]] tag t1; 394 | [[maybe_unused]] tag t2; 395 | [[maybe_unused]] tag t3; 396 | [[maybe_unused]] tag t4; 397 | } 398 | 399 | template 400 | void make_it(Args... args) 401 | { 402 | } 403 | 404 | template 405 | T step_it(T value) 406 | { 407 | return value+1; 408 | } 409 | 410 | template 411 | int sum(T... args) 412 | { 413 | return (... + args); 414 | } 415 | 416 | template 417 | void do_sums(T... args) 418 | { 419 | auto s1 = sum(args...); 420 | auto s2 = sum(42, args...); 421 | auto s3 = sum(step_it(args)...); 422 | } 423 | 424 | template 425 | struct sum_wrapper 426 | { 427 | sum_wrapper(T... args) 428 | { 429 | value = (... + args); 430 | } 431 | 432 | std::common_type_t value; 433 | }; 434 | 435 | template 436 | void parenthesized(T... args) 437 | { 438 | std::array, sizeof...(T)> arr {args...}; 439 | 440 | sum_wrapper sw1(args...); // value = 1 + 2 + 3 + 4 441 | sum_wrapper sw2(++args...); // value = 2 + 3 + 4 + 5 442 | } 443 | 444 | template 445 | void brace_enclosed(T... args) 446 | { 447 | int arr1[sizeof...(args) + 1] = {args..., 0}; // 1,2,3,4,5 448 | int arr2[sizeof...(args)] = { step_it(args)... };// 2,3,4,5 449 | } 450 | 451 | struct A 452 | { 453 | void execute() { std::cout << "A::execute\n"; } 454 | }; 455 | struct B 456 | { 457 | void execute() { std::cout << "B::execute\n"; } 458 | }; 459 | struct C 460 | { 461 | void execute() { std::cout << "C::execute\n"; } 462 | }; 463 | 464 | template 465 | struct X : public Bases... 466 | { 467 | X(Bases const & ... args) : Bases(args)... 468 | { 469 | } 470 | 471 | using Bases::execute...; 472 | }; 473 | 474 | template 475 | void captures(T... args) 476 | { 477 | auto l = [args...]{ return sum(step_it(args)...); }; 478 | auto s = l(); 479 | } 480 | 481 | template 482 | auto make_array(T... args) 483 | { 484 | return std::array, sizeof...(T)> {args...}; 485 | }; 486 | 487 | template 488 | struct alignment1 489 | { 490 | alignas(T...) char a; 491 | }; 492 | 493 | template 494 | struct alignment2 495 | { 496 | alignas(args...) char a; 497 | }; 498 | } 499 | 500 | int main() 501 | { 502 | { 503 | using namespace n301; 504 | 505 | std::cout << "min(42, 7)=" << min(2, 42, 7) << '\n'; 506 | std::cout << "min(1,5,3,-4,9)=" << min(5, 1, 5, 3, -4, 9) << '\n'; 507 | } 508 | 509 | { 510 | using namespace n302; 511 | 512 | std::cout << "min(42.0, 7.5)=" << min(2, 42.0, 7.5) << '\n'; 513 | std::cout << "min(1,5,3,-4,9)=" << min(5, 1, 5, 3, -4, 9) << '\n'; 514 | } 515 | 516 | { 517 | using namespace n303; 518 | 519 | std::cout << "min(42.0, 7.5)=" << min(42.0, 7.5) << '\n'; 520 | std::cout << "min(1,5,3,-4,9)=" << min(1, 5, 3, -4, 9) << '\n'; 521 | } 522 | 523 | { 524 | using namespace n304; 525 | 526 | std::cout << "min(42, 7)=" << min(42, 7) << '\n'; 527 | std::cout << "min(1,5,3,-4,9)=" << min(1, 5, 3, -4, 9) << '\n'; 528 | } 529 | 530 | { 531 | using namespace n305; 532 | 533 | min(1, 5, 3, -4, 9); 534 | } 535 | 536 | { 537 | using namespace n306; 538 | 539 | std::cout << sum(1, 2, 3, 4, 5) << '\n'; 540 | std::cout << sum(1) << '\n'; 541 | } 542 | 543 | { 544 | using namespace n307; 545 | 546 | std::cout << sum(1, 2, 3, 4, 5) << '\n'; 547 | std::cout << sum(1) << '\n'; 548 | } 549 | 550 | { 551 | using namespace n308; 552 | 553 | auto sizes = get_type_sizes(); 554 | for (auto const& s : sizes) 555 | std::cout << s << '\n'; 556 | } 557 | 558 | { 559 | using namespace n310; 560 | multipacks(1, 2, 3, 4, 5, 6); // 1,5 561 | multipacks(1, 2, 3, 4, 5, 6); // 3,3 562 | multipacks(1, 2, 3, 4, 5, 6); // 4,2 563 | multipacks(1, 2, 3, 4, 5, 6); // 6,0 564 | 565 | multipacks(1, 2, 4.0, 5.0, 6.0); // 2,3 566 | multipacks(1, 2, 3, 4.0, 5.0, 6.0); // 3,3 567 | } 568 | 569 | { 570 | using namespace n311; 571 | //multipacks(1, 2, 3, 4, 5, 6); // error 572 | multipacks(1, 2, 3, 4, 5, 6); // OK 573 | //multipacks(1, 2, 3, 4, 5, 6); // error 574 | //multipacks(1, 2, 3, 4, 5, 6); // error 575 | 576 | //multipacks(1, 2, 4.0, 5.0, 6.0); // error 577 | multipacks(1, 2, 3, 4.0, 5.0, 6.0); // OK 578 | } 579 | 580 | { 581 | using namespace n312; 582 | 583 | func_pair funcs{ twice_as, sum_and_div }; 584 | funcs.f(42, 12); 585 | funcs.g(42, 12, 10.0); 586 | } 587 | 588 | { 589 | using namespace n313; 590 | 591 | tuple one(42); 592 | tuple two(42, 42.0); 593 | tuple three(42, 42.0, 'a'); 594 | 595 | std::cout << one.value << '\n'; 596 | std::cout << two.value << ',' 597 | << two.rest.value << '\n'; 598 | std::cout << three.value << ',' 599 | << three.rest.value << ',' 600 | << three.rest.rest.value << '\n'; 601 | 602 | std::cout << get<0>(one) << '\n'; 603 | std::cout << get<0>(two) << ',' 604 | << get<1>(two) << '\n'; 605 | std::cout << get<0>(three) << ',' 606 | << get<1>(three) << ',' 607 | << get<2>(three) << '\n'; 608 | } 609 | 610 | { 611 | using namespace n314; 612 | 613 | // std::cout << sum() << '\n'; // error 614 | std::cout << sum(1) << '\n'; 615 | std::cout << sum(1, 2) << '\n'; 616 | std::cout << sum(1, 2, 3, 4, 5) << '\n'; 617 | 618 | std::cout << sum_from_zero() << '\n'; 619 | std::cout << sum_from_zero(1, 2, 3) << '\n'; 620 | } 621 | 622 | { 623 | using namespace n315; 624 | 625 | printl('d', 'o', 'g'); // dog 626 | printr('d', 'o', 'g'); // dog 627 | print('d', 'o', 'g'); // dog 628 | } 629 | 630 | { 631 | using namespace n315; 632 | 633 | std::vector v; 634 | push_back_many(v, 1, 2, 3, 4, 5); 635 | } 636 | 637 | { 638 | using namespace n316; 639 | 640 | std::cout << Sum<1> << '\n'; 641 | std::cout << Sum<1, 2> << '\n'; 642 | std::cout << Sum<1, 2, 3, 4, 5> << '\n'; 643 | } 644 | 645 | { 646 | using namespace n317; 647 | 648 | [[maybe_unused]] foo f1; 649 | foo f2; 650 | int_foo f3; 651 | static_assert(std::is_same_v); 652 | } 653 | 654 | { 655 | using namespace n317; 656 | 657 | std::tuple t1{ 42, 'x', 42.99 }; 658 | auto t2 = select_tuple(t1, index_sequence<0, 2>{}); 659 | } 660 | 661 | { 662 | using namespace n318; 663 | 664 | [[maybe_unused]] outer a; 665 | 666 | tagger(); 667 | 668 | make_it(42); 669 | make_it(42, 'a'); 670 | 671 | do_sums(1, 2, 3, 4); 672 | 673 | parenthesized(1, 2, 3, 4); 674 | 675 | brace_enclosed(1, 2, 3, 4); 676 | 677 | captures(1, 2, 3, 4); 678 | 679 | auto arr = make_array(1, 2, 3, 4); 680 | 681 | alignment1 al1; 682 | al1.a = 'a'; 683 | 684 | //alignment2<1, 4, 8> al2; // error with VC++ 685 | //al2.a = 'b'; 686 | } 687 | 688 | { 689 | using namespace n318; 690 | 691 | A a; 692 | B b; 693 | C c; 694 | X x(a, b, c); 695 | 696 | x.A::execute(); 697 | x.B::execute(); 698 | x.C::execute(); 699 | } 700 | } -------------------------------------------------------------------------------- /src/chapter_04/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB headers *.h) 2 | add_executable(chapter_04 main.cpp ${headers}) -------------------------------------------------------------------------------- /src/chapter_05/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB headers *.h) 2 | add_executable(chapter_05 main.cpp ${headers}) -------------------------------------------------------------------------------- /src/chapter_05/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | constexpr bool always_false = std::false_type::value; 9 | 10 | namespace n501 11 | { 12 | template 13 | struct is_floating_point 14 | { 15 | static const bool value = false; 16 | }; 17 | 18 | template <> 19 | struct is_floating_point 20 | { 21 | static const bool value = true; 22 | }; 23 | 24 | template <> 25 | struct is_floating_point 26 | { 27 | static const bool value = true; 28 | }; 29 | 30 | template <> 31 | struct is_floating_point 32 | { 33 | static const bool value = true; 34 | }; 35 | 36 | template 37 | void process_real_number(T const value) 38 | { 39 | static_assert(is_floating_point::value); 40 | 41 | std::cout << "processing a real number: " << value << '\n'; 42 | } 43 | } 44 | 45 | namespace n502 46 | { 47 | struct widget 48 | { 49 | int id; 50 | std::string name; 51 | 52 | std::ostream& write(std::ostream& os) const 53 | { 54 | os << id << ',' << name << '\n'; 55 | return os; 56 | } 57 | }; 58 | 59 | struct gadget 60 | { 61 | int id; 62 | std::string name; 63 | 64 | friend std::ostream& operator <<(std::ostream& os, gadget const& o); 65 | }; 66 | 67 | std::ostream& operator <<(std::ostream& os, gadget const& o) 68 | { 69 | os << o.id << ',' << o.name << '\n'; 70 | return os; 71 | } 72 | 73 | template 74 | struct uses_write 75 | { 76 | static constexpr bool value = false; 77 | }; 78 | 79 | template <> 80 | struct uses_write 81 | { 82 | static constexpr bool value = true; 83 | }; 84 | 85 | template 86 | inline constexpr bool uses_write_v = uses_write::value; 87 | 88 | template 89 | struct serializer 90 | { 91 | template 92 | static void serialize(std::ostream& os, T const& value) 93 | { 94 | os << value; 95 | } 96 | }; 97 | 98 | template<> 99 | struct serializer 100 | { 101 | template 102 | static void serialize(std::ostream& os, T const& value) 103 | { 104 | value.write(os); 105 | } 106 | }; 107 | 108 | template 109 | void serialize(std::ostream& os, T const& value) 110 | { 111 | serializer>::serialize(os, value); 112 | } 113 | } 114 | 115 | namespace n503 116 | { 117 | template 118 | auto begin(T& c) { return c.begin(); } 119 | 120 | template 121 | T* begin(T(&arr)[N]) {return arr; } 122 | 123 | template 124 | void increment(T& val) { val++; } 125 | 126 | template 127 | void handle(T(&arr)[N], char(*)[N % 2 == 0] = 0) 128 | { 129 | std::cout << "handle even array\n"; 130 | } 131 | 132 | template 133 | void handle(T(&arr)[N], char(*)[N % 2 == 1] = 0) 134 | { 135 | std::cout << "handle odd array\n"; 136 | } 137 | } 138 | 139 | namespace n504 140 | { 141 | template 142 | struct foo 143 | { 144 | using foo_type = T; 145 | }; 146 | 147 | template 148 | struct bar 149 | { 150 | using bar_type = T; 151 | }; 152 | 153 | struct int_foo : foo {}; 154 | struct int_bar : bar {}; 155 | 156 | template 157 | decltype(typename T::foo_type(), void()) handle(T const& v) 158 | { 159 | std::cout << "handle a foo\n"; 160 | } 161 | 162 | template 163 | decltype(typename T::bar_type(), void()) handle(T const& v) 164 | { 165 | std::cout << "handle a bar\n"; 166 | } 167 | } 168 | 169 | namespace n505 170 | { 171 | template 172 | struct enable_if {}; 173 | 174 | template 175 | struct enable_if 176 | { 177 | using type = T; 178 | }; 179 | 180 | template >::type* = nullptr> 181 | void serialize(std::ostream& os, T const& value) 182 | { 183 | value.write(os); 184 | } 185 | 186 | template >::type* = nullptr> 187 | void serialize(std::ostream& os, T const& value) 188 | { 189 | os << value; 190 | } 191 | } 192 | 193 | namespace n506 194 | { 195 | template 196 | typename std::enable_if>::type serialize(std::ostream& os, T const& value) 197 | { 198 | value.write(os); 199 | } 200 | 201 | template 202 | typename std::enable_if>::type serialize(std::ostream& os, T const& value) 203 | { 204 | os << value; 205 | } 206 | } 207 | 208 | namespace n507 209 | { 210 | template 211 | void serialize(std::ostream& os, T const& value, typename std::enable_if>::type* = nullptr) 212 | { 213 | value.write(os); 214 | } 215 | 216 | template 217 | void serialize(std::ostream& os, T const& value, typename std::enable_if>::type* = nullptr) 218 | { 219 | os << value; 220 | } 221 | } 222 | 223 | namespace n508 224 | { 225 | template >> 226 | struct integral_wrapper 227 | { 228 | T value; 229 | 230 | integral_wrapper(T v) : value(v) {} 231 | }; 232 | 233 | template >> 234 | struct floating_wrapper 235 | { 236 | T value; 237 | 238 | floating_wrapper(T v) : value(v) {} 239 | }; 240 | } 241 | 242 | namespace n509 243 | { 244 | template 245 | void serialize(std::ostream& os, T const& value) 246 | { 247 | if constexpr (n502::uses_write_v) 248 | value.write(os); 249 | else 250 | os << value; 251 | } 252 | } 253 | 254 | namespace n510 255 | { 256 | template 257 | constexpr unsigned int factorial() 258 | { 259 | if constexpr (n > 1) 260 | return n * factorial(); 261 | else 262 | return 1; 263 | } 264 | } 265 | 266 | namespace n511 267 | { 268 | template 269 | bool are_equal(T const& a, T const& b) 270 | { 271 | if constexpr (std::is_floating_point_v) 272 | return std::abs(a - b) < 0.001; 273 | else 274 | return a == b; 275 | } 276 | } 277 | 278 | namespace n512 279 | { 280 | template 281 | void f() 282 | { 283 | if constexpr (std::is_arithmetic_v) 284 | { 285 | 286 | } 287 | else 288 | static_assert(always_false, "Must be arithmetic"); // ill-formed: invalid for every T 289 | } 290 | } 291 | 292 | namespace n513 293 | { 294 | template 295 | std::string as_string(T value) 296 | { 297 | if constexpr (std::is_null_pointer_v) 298 | return "null"; 299 | else if constexpr (std::is_arithmetic_v) 300 | return std::to_string(value); 301 | else 302 | static_assert(always_false); 303 | } 304 | } 305 | 306 | namespace n514 307 | { 308 | struct foo 309 | { 310 | int a; 311 | }; 312 | 313 | struct bar 314 | { 315 | int a = 0; 316 | }; 317 | 318 | struct tar 319 | { 320 | int a = 0; 321 | tar() : a(0) {} 322 | }; 323 | } 324 | 325 | namespace n515 326 | { 327 | template 328 | std::string as_string(T value) 329 | { 330 | if constexpr (std::is_null_pointer_v) 331 | return "null"; 332 | else if constexpr (std::is_same_v) 333 | return value ? "true" : "false"; 334 | else if constexpr (std::is_arithmetic_v) 335 | return std::to_string(value); 336 | else 337 | static_assert(always_false); 338 | } 339 | } 340 | 341 | namespace n516 342 | { 343 | template 344 | std::string as_string(T&& value) 345 | { 346 | if constexpr (std::is_null_pointer_v) 347 | return "null"; 348 | else if constexpr (std::is_same_v) 349 | return value ? "true" : "false"; 350 | else if constexpr (std::is_arithmetic_v) 351 | return std::to_string(value); 352 | else 353 | static_assert(always_false); 354 | } 355 | } 356 | 357 | namespace n517 358 | { 359 | template 360 | std::string as_string(T&& value) 361 | { 362 | using value_type = std::decay_t; 363 | 364 | if constexpr (std::is_null_pointer_v) 365 | return "null"; 366 | else if constexpr (std::is_same_v) 367 | return value ? "true" : "false"; 368 | else if constexpr (std::is_arithmetic_v) 369 | return std::to_string(value); 370 | else 371 | static_assert(always_false); 372 | } 373 | } 374 | 375 | namespace n518 376 | { 377 | template 378 | using list_t = typename std::conditional>::type; 379 | } 380 | 381 | namespace n519 382 | { 383 | template 384 | struct has_common_type : std::false_type {}; 385 | 386 | template 387 | struct has_common_type>, Ts...> 388 | : std::true_type {}; 389 | 390 | template 391 | constexpr bool has_common_type_v = 392 | sizeof...(Ts) < 2 || 393 | has_common_type::value; 394 | 395 | template>> 397 | void process(Ts&&... ts) 398 | { 399 | //static_assert(has_common_type_v, 400 | // "Arguments must have a common type."); 401 | 402 | std::cout << typeid(std::common_type_t).name() << '\n'; 403 | } 404 | } 405 | 406 | namespace n520 407 | { 408 | namespace detail 409 | { 410 | template 411 | struct copy_fn 412 | { 413 | template 414 | constexpr static OutputIt copy(InputIt first, InputIt last, OutputIt d_first) 415 | { 416 | while (first != last) 417 | { 418 | *d_first++ = *first++; 419 | } 420 | return d_first; 421 | } 422 | }; 423 | 424 | template <> 425 | struct copy_fn 426 | { 427 | template 428 | constexpr static OutputIt* copy(InputIt* first, InputIt* last, OutputIt* d_first) 429 | { 430 | std::memmove(d_first, first, (last - first) * sizeof(InputIt)); 431 | return d_first + (last - first); 432 | } 433 | }; 434 | } 435 | 436 | template 437 | constexpr OutputIt copy(InputIt first, InputIt last, OutputIt d_first) 438 | { 439 | using input_type = std::remove_cv_t::value_type>; 440 | using output_type = std::remove_cv_t::value_type>; 441 | 442 | constexpr bool opt = 443 | std::is_same_v && 444 | std::is_pointer_v && 445 | std::is_pointer_v && 446 | std::is_trivially_copy_assignable_v; 447 | 448 | return detail::copy_fn::copy(first, last, d_first); 449 | } 450 | } 451 | 452 | 453 | 454 | int main() 455 | { 456 | { 457 | using namespace n501; 458 | 459 | static_assert(is_floating_point::value); 460 | static_assert(is_floating_point::value); 461 | static_assert(is_floating_point::value); 462 | static_assert(!is_floating_point::value); 463 | static_assert(!is_floating_point::value); 464 | 465 | process_real_number(42.0); 466 | //process_real_number(42); // error: static assertion failed 467 | } 468 | 469 | { 470 | using namespace n502; 471 | 472 | widget w{ 1, "one" }; 473 | gadget g{ 2, "two" }; 474 | 475 | w.write(std::cout); 476 | std::cout << g; 477 | 478 | serialize(std::cout, w); 479 | serialize(std::cout, g); 480 | } 481 | 482 | { 483 | std::array arr1{ 1,2,3,4,5 }; 484 | std::cout << *n503::begin(arr1) << '\n'; 485 | 486 | int arr2[]{ 5,4,3,2,1 }; 487 | std::cout << *n503::begin(arr2) << '\n'; 488 | } 489 | 490 | { 491 | int a = 42; 492 | n503::increment(a); // OK 493 | 494 | std::string s{ "42" }; 495 | // n503::increment(s); // error 496 | } 497 | 498 | { 499 | int arr1[]{ 1,2,3,4,5 }; 500 | n503::handle(arr1); 501 | 502 | int arr2[]{ 1,2,3,4 }; 503 | n503::handle(arr2); 504 | } 505 | 506 | { 507 | using namespace n504; 508 | 509 | int_foo fi; 510 | int_bar bi; 511 | int x = 0; 512 | handle(fi); 513 | handle(bi); 514 | //handle(x); 515 | } 516 | 517 | { 518 | n502::widget w{ 1, "one" }; 519 | n502::gadget g{ 2, "two" }; 520 | 521 | n505::serialize(std::cout, w); 522 | n505::serialize(std::cout, g); 523 | } 524 | 525 | { 526 | n502::widget w{ 1, "one" }; 527 | n502::gadget g{ 2, "two" }; 528 | 529 | n506::serialize(std::cout, w); 530 | n506::serialize(std::cout, g); 531 | } 532 | 533 | { 534 | n502::widget w{ 1, "one" }; 535 | n502::gadget g{ 2, "two" }; 536 | 537 | n507::serialize(std::cout, w); 538 | n507::serialize(std::cout, g); 539 | } 540 | 541 | { 542 | using namespace n508; 543 | 544 | integral_wrapper w1{ 42 }; // OK 545 | //integral_wrapper w2{ 42.0 }; // error 546 | //integral_wrapper w3{ "42" }; // error 547 | 548 | //floating_wrapper w4{ 42 }; // error 549 | floating_wrapper w5{ 42.0 }; // OK 550 | //floating_wrapper w6{ "42" }; // error 551 | } 552 | 553 | { 554 | n502::widget w{ 1, "one" }; 555 | n502::gadget g{ 2, "two" }; 556 | 557 | n509::serialize(std::cout, w); 558 | n509::serialize(std::cout, g); 559 | } 560 | 561 | { 562 | std::cout << n510::factorial<1>() << '\n'; 563 | std::cout << n510::factorial<2>() << '\n'; 564 | std::cout << n510::factorial<3>() << '\n'; 565 | std::cout << n510::factorial<4>() << '\n'; 566 | std::cout << n510::factorial<5>() << '\n'; 567 | } 568 | 569 | { 570 | using namespace n511; 571 | 572 | are_equal(1, 1); 573 | are_equal(1.999998, 1.999997); 574 | are_equal(std::string{ "1" }, std::string{ "1" }); 575 | //are_equal(n502::widget{ 1, "one" }, n502::widget{ 1, "two" }); 576 | } 577 | 578 | { 579 | using namespace n512; 580 | f(); 581 | f(); 582 | //f(); 583 | } 584 | 585 | { 586 | using namespace n513; 587 | std::cout << as_string(nullptr) << '\n'; 588 | std::cout << as_string(true) << '\n'; 589 | std::cout << as_string('a') << '\n'; 590 | std::cout << as_string(42) << '\n'; 591 | std::cout << as_string(42.0) << '\n'; 592 | //std::cout << as_string("42") << '\n'; // error 593 | } 594 | 595 | { 596 | using namespace n514; 597 | 598 | std::cout << std::boolalpha; 599 | std::cout << std::is_trivial_v << '\n'; 600 | std::cout << std::is_trivial_v << '\n'; 601 | std::cout << std::is_trivial_v << '\n'; 602 | 603 | std::cout << std::is_trivially_copyable_v << '\n'; 604 | std::cout << std::is_trivially_copyable_v << '\n'; 605 | std::cout << std::is_trivially_copyable_v << '\n'; 606 | } 607 | 608 | { 609 | using namespace n515; 610 | std::cout << as_string(nullptr) << '\n'; 611 | std::cout << as_string(true) << '\n'; 612 | std::cout << as_string('a') << '\n'; 613 | std::cout << as_string(42) << '\n'; 614 | std::cout << as_string(42.0) << '\n'; 615 | } 616 | 617 | { 618 | using namespace n516; 619 | std::cout << as_string(nullptr) << '\n'; 620 | std::cout << as_string(true) << '\n'; 621 | std::cout << as_string('a') << '\n'; 622 | std::cout << as_string(42) << '\n'; 623 | std::cout << as_string(42.0) << '\n'; 624 | 625 | //bool f = true; 626 | //std::cout << as_string(f) << '\n'; 627 | 628 | //int n = 42; 629 | //std::cout << as_string(n) << '\n'; 630 | } 631 | 632 | { 633 | using namespace n517; 634 | std::cout << as_string(nullptr) << '\n'; 635 | std::cout << as_string(true) << '\n'; 636 | std::cout << as_string('a') << '\n'; 637 | std::cout << as_string(42) << '\n'; 638 | std::cout << as_string(42.0) << '\n'; 639 | 640 | bool f = true; 641 | std::cout << as_string(f) << '\n'; 642 | 643 | int n = 42; 644 | std::cout << as_string(n) << '\n'; 645 | } 646 | 647 | { 648 | using namespace n518; 649 | 650 | static_assert(std::is_same_v, int>); 651 | static_assert(std::is_same_v, std::vector>); 652 | } 653 | 654 | { 655 | using namespace n519; 656 | 657 | process(1); // int 658 | process(1, 2, 3); // int 659 | process(1, 2.0, '3'); // double 660 | //process(1, 2.0, "3"); // error 661 | } 662 | 663 | { 664 | std::vector v1{ 1, 2, 3, 4, 5 }; 665 | std::vector v2(5); 666 | 667 | n520::copy(std::begin(v1), std::end(v1), std::begin(v2)); 668 | 669 | int a1[5] = { 1,2,3,4,5 }; 670 | int a2[5]; 671 | 672 | n520::copy(a1, a1 + 5, a2); 673 | } 674 | } -------------------------------------------------------------------------------- /src/chapter_06/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB headers *.h) 2 | add_executable(chapter_06 main.cpp ${headers}) -------------------------------------------------------------------------------- /src/chapter_06/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace n601 10 | { 11 | template 12 | T add(T const a, T const b) 13 | { 14 | return a + b; 15 | } 16 | } 17 | 18 | namespace n602 19 | { 20 | template >> 22 | T add(T const a, T const b) 23 | { 24 | return a + b; 25 | } 26 | } 27 | 28 | namespace n603 29 | { 30 | template 31 | T add(T const a, T const b) 32 | { 33 | static_assert(std::is_arithmetic_v, "Arithmetic type required"); 34 | return a + b; 35 | } 36 | } 37 | 38 | namespace n604 39 | { 40 | template 41 | requires std::is_arithmetic_v 42 | T add(T const a, T const b) 43 | { 44 | return a + b; 45 | } 46 | } 47 | 48 | namespace n605 49 | { 50 | template 51 | T add(T const a, T const b) requires std::is_arithmetic_v 52 | { 53 | return a + b; 54 | } 55 | } 56 | 57 | namespace n606 58 | { 59 | template 60 | concept arithmetic = requires { std::is_arithmetic_v; }; 61 | 62 | template 63 | T add(T const a, T const b) 64 | { 65 | return a + b; 66 | } 67 | } 68 | 69 | namespace n607 70 | { 71 | template 72 | concept arithmetic = std::is_arithmetic_v; 73 | 74 | template 75 | T add(T const a, T const b) 76 | { 77 | return a + b; 78 | } 79 | } 80 | 81 | namespace n608 82 | { 83 | template 84 | requires std::is_arithmetic_v 85 | T add(T const a, T const b) 86 | { 87 | return a + b; 88 | } 89 | 90 | template 91 | requires std::is_arithmetic_v 92 | T mul(T const a, T const b) 93 | { 94 | return a * b; 95 | } 96 | } 97 | 98 | namespace n610 99 | { 100 | template 101 | struct is_container : std::false_type {}; 102 | 103 | template 104 | struct is_container().size()), 111 | decltype(std::declval().begin()), 112 | decltype(std::declval().end()), 113 | decltype(std::declval().cbegin()), 114 | decltype(std::declval().cend())>> 115 | : std::true_type{}; 116 | 117 | template 118 | constexpr bool is_container_v = is_container::value; 119 | 120 | struct foo {}; 121 | 122 | static_assert(!is_container_v); 123 | static_assert(is_container_v>); 124 | } 125 | 126 | namespace n611 127 | { 128 | template 129 | concept container = requires(T t) 130 | { 131 | typename T::value_type; 132 | typename T::size_type; 133 | typename T::allocator_type; 134 | typename T::iterator; 135 | typename T::const_iterator; 136 | t.size(); 137 | t.begin(); 138 | t.end(); 139 | t.cbegin(); 140 | t.cend(); 141 | }; 142 | 143 | struct foo{}; 144 | 145 | static_assert(!container); 146 | static_assert(container>); 147 | 148 | template 149 | void process(C&& c) {} 150 | } 151 | 152 | namespace n612 153 | { 154 | template 155 | concept arithmetic = requires 156 | { 157 | std::is_arithmetic_v; 158 | }; 159 | 160 | template 161 | concept addable = requires(T a, T b) 162 | { 163 | a + b; 164 | }; 165 | 166 | template 167 | concept logger = requires(T t) 168 | { 169 | t.error("just"); 170 | t.warning("a"); 171 | t.info("demo"); 172 | }; 173 | 174 | template 175 | void log_error(T& logger) 176 | { 177 | } 178 | 179 | struct console_logger 180 | { 181 | void error(std::string_view text){} 182 | void warning(std::string_view text) {} 183 | void info(std::string_view text) {} 184 | }; 185 | 186 | struct stream_logger 187 | { 188 | void error(std::string_view text, bool = false) {} 189 | void warning(std::string_view text, bool = false) {} 190 | void info(std::string_view text, bool) {} 191 | }; 192 | } 193 | 194 | namespace n613 195 | { 196 | template 197 | concept KVP = requires { 198 | typename T::key_type; 199 | typename T::value_type; 200 | }; 201 | 202 | template 203 | struct key_value_pair 204 | { 205 | using key_type = T; 206 | using value_type = V; 207 | 208 | key_type key; 209 | value_type value; 210 | }; 211 | 212 | static_assert(KVP>); 213 | static_assert(!KVP>); 214 | 215 | template 216 | requires std::is_arithmetic_v 217 | struct container 218 | { /* ... */ }; 219 | 220 | template 221 | concept containerizeable = requires { 222 | typename container; 223 | }; 224 | 225 | static_assert(containerizeable); 226 | static_assert(!containerizeable); 227 | } 228 | 229 | namespace n614 230 | { 231 | template 232 | void f(T) noexcept {} 233 | 234 | template 235 | void g(T) {} 236 | 237 | template 238 | concept NonThrowing = requires(F && func, T ... t) 239 | { 240 | {func(t...)} noexcept; 241 | }; 242 | 243 | template 244 | requires NonThrowing 245 | void invoke(F&& func, T... t) 246 | { 247 | func(t...); 248 | } 249 | } 250 | 251 | namespace n615 252 | { 253 | template 254 | concept timer = requires(T t) 255 | { 256 | {t.start()} -> std::same_as; 257 | {t.stop()} -> std::convertible_to; 258 | }; 259 | 260 | struct timerA 261 | { 262 | void start() {} 263 | long long stop() { return 0; } 264 | }; 265 | 266 | struct timerB 267 | { 268 | void start() {} 269 | int stop() { return 0; } 270 | }; 271 | 272 | struct timerC 273 | { 274 | void start() {} 275 | void stop() {} 276 | long long getTicks() { return 0; } 277 | }; 278 | 279 | static_assert(timer); 280 | static_assert(timer); 281 | static_assert(!timer); 282 | } 283 | 284 | namespace n616 285 | { 286 | template 287 | inline constexpr bool are_same_v = std::conjunction_v...>; 288 | 289 | template 290 | concept HomogenousRange = requires(T... t) 291 | { 292 | (... + t); 293 | requires are_same_v; 294 | requires sizeof...(T) > 1; 295 | }; 296 | 297 | template 298 | requires HomogenousRange 299 | auto add(T&&... t) 300 | { 301 | return (... + t); 302 | } 303 | 304 | static_assert(HomogenousRange); 305 | static_assert(!HomogenousRange); 306 | static_assert(!HomogenousRange); 307 | } 308 | 309 | namespace n617 310 | { 311 | template 312 | requires std::is_integral_v && std::is_signed_v 313 | T decrement(T value) 314 | { 315 | return value--; 316 | } 317 | } 318 | 319 | namespace n618 320 | { 321 | template 322 | concept Integral = std::is_integral_v; 323 | 324 | template 325 | concept Signed = std::is_signed_v; 326 | 327 | template 328 | concept SignedIntegral = Integral && Signed; 329 | 330 | template 331 | T decrement(T value) 332 | { 333 | return value--; 334 | } 335 | } 336 | 337 | namespace n619 338 | { 339 | template 340 | requires std::is_integral_v || std::is_floating_point_v 341 | T add(T a, T b) 342 | { 343 | return a + b; 344 | } 345 | } 346 | 347 | namespace n620 348 | { 349 | template 350 | concept Integral = std::is_integral_v; 351 | 352 | template 353 | concept FloatingPoint = std::is_floating_point_v; 354 | 355 | template 356 | concept Number = Integral || FloatingPoint; 357 | 358 | template 359 | T add(T a, T b) 360 | { 361 | return a + b; 362 | } 363 | } 364 | 365 | namespace n621 366 | { 367 | template 368 | concept A = std::is_integral_v; 369 | 370 | template 371 | concept B = std::is_floating_point_v; 372 | 373 | // disjunctions 374 | template 375 | requires A || B 376 | void f() {} 377 | 378 | template 379 | requires (A || B) 380 | void f() {} 381 | 382 | template 383 | requires A && (!A || B) 384 | void f() {} 385 | 386 | // logical operators 387 | template 388 | requires (!(A || B)) 389 | void f() {} 390 | 391 | template 392 | requires (static_cast(A || B)) 393 | void f() {} 394 | } 395 | 396 | namespace n622 397 | { 398 | template 399 | requires (std::is_integral_v && ...) 400 | auto add(T ... args) 401 | { 402 | return (args + ...); 403 | } 404 | } 405 | 406 | namespace n623 407 | { 408 | template 409 | concept Integral = std::is_integral_v; 410 | 411 | template 412 | requires (Integral && ...) 413 | auto add(T ... args) 414 | { 415 | return (args + ...); 416 | } 417 | } 418 | 419 | namespace n624 420 | { 421 | int add(int a, int b) 422 | { 423 | return a + b; 424 | } 425 | 426 | template 427 | T add(T a, T b) 428 | { 429 | return a + b; 430 | } 431 | } 432 | 433 | namespace n625 434 | { 435 | template 436 | T add(T a, T b) 437 | { 438 | return a + b; 439 | } 440 | 441 | template 442 | requires std::is_integral_v 443 | T add(T a, T b) 444 | { 445 | return a + b; 446 | } 447 | } 448 | 449 | namespace n626 450 | { 451 | template 452 | requires (sizeof(T) == 4) 453 | T add(T a, T b) 454 | { 455 | return a + b; 456 | } 457 | 458 | template 459 | requires std::is_integral_v 460 | T add(T a, T b) 461 | { 462 | return a + b; 463 | } 464 | } 465 | 466 | namespace n627 467 | { 468 | template 469 | requires std::is_integral_v 470 | T add(T a, T b) 471 | { 472 | return a + b; 473 | } 474 | 475 | template 476 | requires std::is_integral_v && (sizeof(T) == 4) 477 | T add(T a, T b) 478 | { 479 | return a + b; 480 | } 481 | } 482 | 483 | namespace n628 484 | { 485 | template 486 | concept Integral = std::is_integral_v; 487 | 488 | template 489 | requires Integral 490 | T add(T a, T b) 491 | { 492 | return a + b; 493 | } 494 | 495 | template 496 | requires Integral && (sizeof(T) == 4) 497 | T add(T a, T b) 498 | { 499 | return a + b; 500 | } 501 | } 502 | 503 | namespace n629 504 | { 505 | template 506 | concept Integral = std::is_integral_v; 507 | 508 | template 509 | T add(T a, T b) 510 | { 511 | return a + b; 512 | } 513 | 514 | template 515 | requires (sizeof(T) == 4) 516 | T add(T a, T b) 517 | { 518 | return a + b; 519 | } 520 | } 521 | 522 | namespace n630 523 | { 524 | template 525 | struct wrapper 526 | { 527 | T value; 528 | 529 | bool operator==(std::string_view str) 530 | requires std::is_convertible_v 531 | { 532 | return value == str; 533 | } 534 | }; 535 | } 536 | 537 | namespace n631a 538 | { 539 | template 540 | struct wrapper 541 | { 542 | T value; 543 | 544 | wrapper(T const & v) :value(v) {} 545 | }; 546 | } 547 | 548 | namespace n631b 549 | { 550 | template 551 | struct wrapper 552 | { 553 | T value; 554 | 555 | template && 557 | std::is_convertible_v>> 558 | wrapper(U const& v) :value(v) {} 559 | }; 560 | } 561 | 562 | namespace n631c 563 | { 564 | template 565 | struct wrapper 566 | { 567 | T value; 568 | 569 | wrapper(T const& v) 570 | requires std::is_copy_constructible_v 571 | :value(v) {} 572 | }; 573 | } 574 | 575 | namespace n632a 576 | { 577 | void handle(int v) 578 | { /* do something else */ } 579 | 580 | //void handle(long v) 581 | // requires (sizeof(long) > sizeof(int)) 582 | //{ /* do something else */ } 583 | } 584 | 585 | namespace n632b 586 | { 587 | void handle(long v) 588 | { 589 | if constexpr (sizeof(long) > sizeof(int)) 590 | { 591 | /* do something else */ 592 | } 593 | else 594 | { 595 | /* do something */ 596 | } 597 | } 598 | } 599 | 600 | namespace n633a 601 | { 602 | template 603 | struct wrapper 604 | { 605 | T value; 606 | }; 607 | } 608 | 609 | namespace n633b 610 | { 611 | template 612 | struct wrapper 613 | { 614 | T value; 615 | }; 616 | 617 | template 618 | requires (sizeof(T) == 4) 619 | struct wrapper 620 | { 621 | union 622 | { 623 | T value; 624 | struct 625 | { 626 | uint8_t byte4; 627 | uint8_t byte3; 628 | uint8_t byte2; 629 | uint8_t byte1; 630 | }; 631 | }; 632 | }; 633 | } 634 | 635 | namespace n634 636 | { 637 | template 638 | constexpr T PI = T(3.1415926535897932385L); 639 | } 640 | 641 | namespace n635a 642 | { 643 | template 644 | using integral_vector = std::vector; 645 | } 646 | 647 | namespace n635b 648 | { 649 | template 650 | requires std::integral 651 | using integral_vector = std::vector; 652 | } 653 | 654 | namespace n636a 655 | { 656 | auto add(auto a, auto b) 657 | { 658 | return a + b; 659 | } 660 | 661 | template<> 662 | auto add(char const* a, char const* b) 663 | { 664 | return std::string(a) + std::string(b); 665 | } 666 | } 667 | 668 | namespace n636b 669 | { 670 | auto add(std::integral auto a, std::integral auto b) 671 | { 672 | return a + b; 673 | } 674 | } 675 | 676 | namespace n636c 677 | { 678 | auto add(std::integral auto ... args) 679 | { 680 | return (args + ...); 681 | } 682 | } 683 | 684 | namespace n637a 685 | { 686 | template 687 | concept addable = requires(T a, T b) { a + b; }; // requires expression 688 | 689 | template 690 | requires addable // requires clause with concept 691 | auto add(T a, T b) 692 | { 693 | return a + b; 694 | } 695 | } 696 | 697 | namespace n637b 698 | { 699 | template 700 | requires requires(T a, T b) { a + b; } // requires clause with requires expression 701 | auto add(T a, T b) 702 | { 703 | return a + b; 704 | } 705 | } 706 | 707 | int main() 708 | { 709 | { 710 | using namespace n601; 711 | using namespace std::string_literals; 712 | 713 | add(42, 1); 714 | add(42.0, 1.0); 715 | add("42"s, "1"s); 716 | //add("42", "1"); // error: cannot add two pointers 717 | } 718 | 719 | { 720 | using namespace n602; 721 | using namespace std::string_literals; 722 | 723 | add(42, 1); 724 | add(42.0, 1.0); 725 | //add("42"s, "1"s); // error: no matching overloaded function found 726 | //add("42", "1"); // error: no matching overloaded function found 727 | } 728 | 729 | { 730 | using namespace n603; 731 | using namespace std::string_literals; 732 | 733 | add(42, 1); 734 | add(42.0, 1.0); 735 | //add("42"s, "1"s); // error: Arithmetic type required 736 | //add("42", "1"); // error: Arithmetic type required 737 | } 738 | 739 | { 740 | using namespace n604; 741 | using namespace std::string_literals; 742 | 743 | add(42, 1); 744 | add(42.0, 1.0); 745 | //add("42"s, "1"s); // error: the associated constraints are not satisfied 746 | //add("42", "1"); // error: the associated constraints are not satisfied 747 | } 748 | 749 | { 750 | using namespace n605; 751 | using namespace std::string_literals; 752 | 753 | add(42, 1); 754 | add(42.0, 1.0); 755 | //add("42"s, "1"s); // error: the associated constraints are not satisfied 756 | //add("42", "1"); // error: the associated constraints are not satisfied 757 | } 758 | 759 | { 760 | using namespace n606; 761 | using namespace std::string_literals; 762 | 763 | add(42, 1); 764 | add(42.0, 1.0); 765 | //add("42"s, "1"s); // error: the associated constraints are not satisfied 766 | //add("42", "1"); // error: the associated constraints are not satisfied 767 | } 768 | 769 | { 770 | using namespace n607; 771 | using namespace std::string_literals; 772 | 773 | add(42, 1); 774 | add(42.0, 1.0); 775 | //add("42"s, "1"s); // error: the associated constraints are not satisfied 776 | //add("42", "1"); // error: the associated constraints are not satisfied 777 | } 778 | 779 | { 780 | using namespace n612; 781 | 782 | console_logger cl; 783 | log_error(cl); 784 | 785 | [[maybe_unused]] stream_logger sl; 786 | // log_error(sl); // error: the associated constraints are not satisfied 787 | } 788 | 789 | { 790 | using namespace n614; 791 | 792 | invoke(f, 42); 793 | //invoke(g, 42); // error 794 | } 795 | 796 | { 797 | using namespace n616; 798 | 799 | add(1, 2); 800 | //add(1); 801 | //add(1, 2.0); 802 | } 803 | 804 | { 805 | using namespace n622; 806 | 807 | add(1, 2, 3); 808 | //add(1, 42.0); 809 | } 810 | 811 | { 812 | using namespace n623; 813 | 814 | add(1, 2, 3); 815 | //add(1, 42.0); 816 | } 817 | 818 | { 819 | using namespace n624; 820 | 821 | add(1.0, 2.0); 822 | add(1, 2); 823 | } 824 | 825 | { 826 | using namespace n625; 827 | 828 | add(1.0, 2.0); 829 | add(1, 2); 830 | } 831 | 832 | { 833 | using namespace n626; 834 | 835 | add((short)1, (short)2); 836 | //add(1, 2); 837 | } 838 | 839 | { 840 | using namespace n627; 841 | 842 | add((short)1, (short)2); 843 | //add(1, 2); 844 | } 845 | 846 | { 847 | using namespace n628; 848 | 849 | add((short)1, (short)2); 850 | add(1, 2); 851 | } 852 | 853 | { 854 | using namespace n629; 855 | 856 | add((short)1, (short)2); 857 | add(1, 2); 858 | } 859 | 860 | { 861 | using namespace n630; 862 | 863 | wrapper a{ 42 }; 864 | wrapper b{ "42" }; 865 | 866 | //if(a == 42) {} // error 867 | if(b == "42") {} 868 | } 869 | 870 | { 871 | using namespace n631a; 872 | 873 | wrapper a = 42; 874 | 875 | //wrapper> p = std::make_unique(42); // error 876 | } 877 | 878 | { 879 | using namespace n631b; 880 | 881 | wrapper a = 42; 882 | 883 | //wrapper> p = std::make_unique(42); //error 884 | } 885 | 886 | { 887 | using namespace n631c; 888 | 889 | wrapper a = 42; 890 | 891 | //wrapper> p = std::make_unique(42); //error 892 | } 893 | 894 | { 895 | using namespace n633a; 896 | 897 | wrapper a{ 42 }; 898 | // wrapper b{ 42.0 }; // error 899 | } 900 | 901 | { 902 | using namespace n633b; 903 | 904 | wrapper a{ 42 }; 905 | std::cout << a.value << '\n'; 906 | 907 | wrapper b{ 0x11223344 }; 908 | std::cout << std::hex << b.value << '\n'; 909 | std::cout << std::hex << (int)b.byte1 << '\n'; 910 | std::cout << std::hex << (int)b.byte2 << '\n'; 911 | std::cout << std::hex << (int)b.byte3 << '\n'; 912 | std::cout << std::hex << (int)b.byte4 << '\n'; 913 | } 914 | 915 | { 916 | using namespace n634; 917 | 918 | std::cout << PI << '\n'; // OK 919 | //std::cout << PI << '\n'; // error 920 | } 921 | 922 | { 923 | using namespace n635a; 924 | 925 | integral_vector v1 { 1,2,3 }; 926 | //integral_vector v2 {1.0, 2.0, 3.0}; // error 927 | } 928 | 929 | { 930 | using namespace n635b; 931 | 932 | integral_vector v1{ 1,2,3 }; 933 | //integral_vector v2 {1.0, 2.0, 3.0}; // error 934 | } 935 | 936 | { 937 | using namespace n636a; 938 | 939 | add(4, 2); 940 | add(4.0, 2); 941 | add("4", "2"); 942 | } 943 | 944 | { 945 | using namespace n636b; 946 | 947 | add(4, 2); 948 | //add(4.2, 0); // error 949 | } 950 | 951 | { 952 | using namespace n636c; 953 | 954 | add(1, 2, 3); 955 | } 956 | } -------------------------------------------------------------------------------- /src/chapter_07/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB headers *.h) 2 | add_executable(chapter_07 main.cpp ${headers}) -------------------------------------------------------------------------------- /src/chapter_07/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace n701 18 | { 19 | struct game_unit 20 | { 21 | virtual void attack() = 0; 22 | }; 23 | 24 | struct knight : game_unit 25 | { 26 | void attack() override 27 | { 28 | std::cout << "draw sword\n"; 29 | } 30 | }; 31 | 32 | struct mage : game_unit 33 | { 34 | void attack() override 35 | { 36 | std::cout << "spell magic curse\n"; 37 | } 38 | }; 39 | 40 | void fight(std::vector const & units) 41 | { 42 | for (auto unit : units) 43 | { 44 | unit->attack(); 45 | } 46 | } 47 | 48 | struct knight_mage : game_unit 49 | { 50 | void attack() override 51 | { 52 | std::cout << "draw magic sword\n"; 53 | } 54 | }; 55 | 56 | struct attack 57 | { 58 | int value; 59 | }; 60 | 61 | struct defence 62 | { 63 | int value; 64 | }; 65 | 66 | attack operator+(attack const& a, int value) 67 | { 68 | return attack{ a.value + value }; 69 | } 70 | 71 | knight_mage operator+(knight const& k, mage const& m) 72 | { 73 | return knight_mage{}; 74 | } 75 | 76 | void increment(attack& a) { a.value++; } 77 | void increment(defence& d) { d.value++; } 78 | 79 | //template 80 | //void increment(T& t) { t.value++; } 81 | } 82 | 83 | namespace n702 84 | { 85 | template 86 | struct Base 87 | { 88 | void f() { static_cast(this)->f(); } 89 | }; 90 | 91 | struct Derived : public Base 92 | { 93 | void f() { std::cout << "Derived::f()\n"; } 94 | }; 95 | 96 | template 97 | void process(Base& b) 98 | { 99 | b.f(); 100 | } 101 | } 102 | 103 | namespace n703 104 | { 105 | template 106 | struct game_unit 107 | { 108 | void attack() 109 | { 110 | static_cast(this)->do_attack(); 111 | } 112 | }; 113 | 114 | struct knight : game_unit 115 | { 116 | void do_attack() 117 | { 118 | std::cout << "draw sword\n"; 119 | } 120 | }; 121 | 122 | struct mage : game_unit 123 | { 124 | void do_attack() 125 | { 126 | std::cout << "spell magic curse\n"; 127 | } 128 | }; 129 | 130 | template 131 | void fight(std::vector*> const & units) 132 | { 133 | for (auto unit : units) 134 | { 135 | unit->attack(); 136 | } 137 | } 138 | } 139 | 140 | namespace n704 141 | { 142 | template 143 | struct limited_instances 144 | { 145 | static std::atomic count; 146 | limited_instances() 147 | { 148 | if (count >= N) 149 | throw std::logic_error{ "Too many instances" }; 150 | ++count; 151 | } 152 | ~limited_instances() { --count; } 153 | }; 154 | 155 | template 156 | std::atomic limited_instances::count = 0; 157 | 158 | struct excalibur : limited_instances {}; 159 | struct book_of_magic : limited_instances {}; 160 | } 161 | 162 | namespace n705 163 | { 164 | template 165 | struct movable_unit 166 | { 167 | void advance(size_t steps) 168 | { 169 | while (steps--) 170 | static_cast(this)->step_forth(); 171 | } 172 | 173 | void retreat(size_t steps) 174 | { 175 | while (steps--) 176 | static_cast(this)->step_back(); 177 | } 178 | }; 179 | 180 | struct knight : movable_unit 181 | { 182 | void step_forth() 183 | { 184 | std::cout << "knight moves forward\n"; 185 | } 186 | 187 | void step_back() 188 | { 189 | std::cout << "knight moves back\n"; 190 | } 191 | }; 192 | 193 | struct mage : movable_unit 194 | { 195 | void step_forth() 196 | { 197 | std::cout << "mage moves forward\n"; 198 | } 199 | 200 | void step_back() 201 | { 202 | std::cout << "mage moves back\n"; 203 | } 204 | }; 205 | } 206 | 207 | namespace n706 208 | { 209 | struct knight 210 | { 211 | void step_forth() 212 | { 213 | std::cout << "knight moves forward\n"; 214 | } 215 | 216 | void step_back() 217 | { 218 | std::cout << "knight moves back\n"; 219 | } 220 | }; 221 | 222 | struct mage 223 | { 224 | void step_forth() 225 | { 226 | std::cout << "mage moves forward\n"; 227 | } 228 | 229 | void step_back() 230 | { 231 | std::cout << "mage moves back\n"; 232 | } 233 | }; 234 | 235 | template 236 | void advance(T& t, size_t steps) 237 | { 238 | while (steps--) 239 | t.step_forth(); 240 | } 241 | 242 | template 243 | void retreat(T& t, size_t steps) 244 | { 245 | while (steps--) 246 | t.step_back(); 247 | } 248 | } 249 | 250 | namespace n707 251 | { 252 | struct hero 253 | { 254 | hero(std::string_view n) : name(n) {} 255 | 256 | void ally_with(hero& u) 257 | { 258 | connections.insert(&u); 259 | u.connections.insert(this); 260 | } 261 | private: 262 | std::string name; 263 | std::set connections; 264 | 265 | friend std::ostream& operator<<(std::ostream& os, hero const& obj); 266 | }; 267 | 268 | std::ostream& operator<<(std::ostream& os, hero const& obj) 269 | { 270 | for (hero* u : obj.connections) 271 | os << obj.name << " --> [" << u->name << "]" << '\n'; 272 | 273 | return os; 274 | } 275 | 276 | struct hero_party : std::vector 277 | {}; 278 | } 279 | 280 | namespace n708 281 | { 282 | template 283 | struct base_unit 284 | { 285 | template 286 | void ally_with(U& other); 287 | }; 288 | 289 | struct hero : base_unit 290 | { 291 | hero(std::string_view n) : name(n) {} 292 | 293 | hero* begin() { return this; } 294 | hero* end() { return this + 1; } 295 | 296 | private: 297 | std::string name; 298 | std::set connections; 299 | 300 | template 301 | friend struct base_unit; 302 | 303 | template 304 | friend std::ostream& operator<<(std::ostream& os, base_unit& object); 305 | }; 306 | 307 | struct hero_party : std::vector, base_unit 308 | {}; 309 | 310 | template 311 | template 312 | void base_unit::ally_with(U& other) 313 | { 314 | for (hero& from : *static_cast(this)) 315 | { 316 | for (hero& to : other) 317 | { 318 | from.connections.insert(&to); 319 | to.connections.insert(&from); 320 | } 321 | } 322 | } 323 | 324 | template 325 | std::ostream& operator<<(std::ostream& os, base_unit& object) 326 | { 327 | for (hero& obj : *static_cast(&object)) 328 | { 329 | for (hero* n : obj.connections) 330 | os << obj.name << " --> [" << n->name << "]" << '\n'; 331 | } 332 | return os; 333 | } 334 | } 335 | 336 | namespace n709a 337 | { 338 | struct building {}; 339 | } 340 | 341 | namespace n709b 342 | { 343 | struct building : std::enable_shared_from_this 344 | { 345 | }; 346 | } 347 | 348 | namespace n709c 349 | { 350 | struct executor 351 | { 352 | void execute(std::function const& task) 353 | { 354 | threads.push_back(std::thread([task]() { 355 | using namespace std::chrono_literals; 356 | std::this_thread::sleep_for(250ms); 357 | 358 | task(); 359 | })); 360 | } 361 | 362 | ~executor() 363 | { 364 | for (auto& t : threads) 365 | t.join(); 366 | } 367 | private: 368 | std::vector threads; 369 | }; 370 | 371 | struct building : std::enable_shared_from_this 372 | { 373 | building() { std::cout << "building created\n"; } 374 | ~building() { std::cout << "building destroyed\n"; } 375 | 376 | void upgrade() 377 | { 378 | if (exec) 379 | { 380 | exec->execute([self = shared_from_this()]() { 381 | self->do_upgrade(); 382 | }); 383 | } 384 | } 385 | 386 | void set_executor(executor* e) 387 | { 388 | exec = e; 389 | } 390 | private: 391 | void do_upgrade() 392 | { 393 | std::cout << "upgrading\n"; 394 | operational = false; 395 | 396 | using namespace std::chrono_literals; 397 | std::this_thread::sleep_for(1000ms); 398 | 399 | operational = true; 400 | std::cout << "building is functional\n"; 401 | } 402 | 403 | bool operational = false; 404 | executor* exec = nullptr; 405 | }; 406 | } 407 | 408 | namespace n710a 409 | { 410 | struct hit_and_run 411 | { 412 | void fight() 413 | { 414 | std::cout << "hit once hard then run\n"; 415 | } 416 | }; 417 | 418 | struct last_man_standing 419 | { 420 | void fight() 421 | { 422 | std::cout << "duel until one falls\n"; 423 | } 424 | }; 425 | 426 | template 427 | struct knight : public Strategy 428 | { 429 | void attack() 430 | { 431 | std::cout << "draw sword\n"; 432 | Strategy::fight(); 433 | } 434 | }; 435 | 436 | template 437 | struct mage : public Strategy 438 | { 439 | void attack() 440 | { 441 | std::cout << "spell magic curse\n"; 442 | Strategy::fight(); 443 | } 444 | }; 445 | } 446 | 447 | namespace n710b 448 | { 449 | struct knight 450 | { 451 | void step_forth() 452 | { 453 | std::cout << "knight moves forward\n"; 454 | } 455 | 456 | void step_back() 457 | { 458 | std::cout << "knight moves back\n"; 459 | } 460 | }; 461 | 462 | struct mage 463 | { 464 | void step_forth() 465 | { 466 | std::cout << "mage moves forward\n"; 467 | } 468 | 469 | void step_back() 470 | { 471 | std::cout << "mage moves back\n"; 472 | } 473 | }; 474 | 475 | template 476 | struct movable_unit : T 477 | { 478 | void advance(size_t steps) 479 | { 480 | while (steps--) 481 | T::step_forth(); 482 | } 483 | 484 | void retreat(size_t steps) 485 | { 486 | while (steps--) 487 | T::step_back(); 488 | } 489 | }; 490 | } 491 | 492 | namespace n710c 493 | { 494 | struct aggressive_style 495 | { 496 | void fight() 497 | { 498 | std::cout << "attack! attack attack!\n"; 499 | } 500 | }; 501 | 502 | struct moderate_style 503 | { 504 | void fight() 505 | { 506 | std::cout << "attack then defend\n"; 507 | } 508 | }; 509 | 510 | template 511 | struct lone_warrior : T 512 | { 513 | void fight() 514 | { 515 | std::cout << "fighting alone."; 516 | T::fight(); 517 | } 518 | }; 519 | 520 | template 521 | struct team_warrior : T 522 | { 523 | void fight() 524 | { 525 | std::cout << "fighting with a team."; 526 | T::fight(); 527 | } 528 | }; 529 | 530 | struct game_unit 531 | { 532 | virtual void attack() = 0; 533 | virtual ~game_unit() = default; 534 | }; 535 | 536 | template 537 | struct knight : T, game_unit 538 | { 539 | void attack() 540 | { 541 | std::cout << "draw sword."; 542 | T::fight(); 543 | } 544 | }; 545 | 546 | template 547 | struct mage : T, game_unit 548 | { 549 | void attack() 550 | { 551 | std::cout << "spell magic curse."; 552 | T::fight(); 553 | } 554 | }; 555 | } 556 | 557 | namespace n711a 558 | { 559 | namespace details 560 | { 561 | template 562 | void advance(Iter& it, Distance n, std::random_access_iterator_tag) 563 | { 564 | it += n; 565 | } 566 | 567 | template 568 | void advance(Iter& it, Distance n, std::bidirectional_iterator_tag) 569 | { 570 | if (n > 0) 571 | { 572 | while (n--) ++it; 573 | } 574 | else 575 | { 576 | while (n++) --it; 577 | } 578 | } 579 | 580 | template 581 | void advance(Iter& it, Distance n, std::input_iterator_tag) 582 | { 583 | while (n--) 584 | { 585 | ++it; 586 | } 587 | } 588 | } 589 | 590 | template 591 | void advance(Iter& it, Distance n) 592 | { 593 | details::advance(it, n, 594 | typename std::iterator_traits::iterator_category{}); 595 | } 596 | } 597 | 598 | namespace n711b 599 | { 600 | template 601 | void advance(Iter& it, Distance n) 602 | { 603 | it += n; 604 | } 605 | 606 | template 607 | void advance(Iter& it, Distance n) 608 | { 609 | if (n > 0) 610 | { 611 | while (n--) ++it; 612 | } 613 | else 614 | { 615 | while (n++) --it; 616 | } 617 | } 618 | 619 | template 620 | void advance(Iter& it, Distance n) 621 | { 622 | while (n--) 623 | { 624 | ++it; 625 | } 626 | } 627 | } 628 | 629 | namespace n712a 630 | { 631 | struct knight 632 | { 633 | void attack() { std::cout << "draw sword\n"; } 634 | }; 635 | 636 | struct mage 637 | { 638 | void attack() { std::cout << "spell magic curse\n"; } 639 | }; 640 | 641 | struct game_unit 642 | { 643 | virtual void attack() = 0; 644 | virtual ~game_unit() = default; 645 | }; 646 | 647 | struct knight_unit : game_unit 648 | { 649 | knight_unit(knight& u) : k(u) {} 650 | void attack() override { k.attack(); } 651 | 652 | private: 653 | knight& k; 654 | }; 655 | 656 | struct mage_unit : game_unit 657 | { 658 | mage_unit(mage& u) : m(u) {} 659 | void attack() override { m.attack(); } 660 | 661 | private: 662 | mage& m; 663 | }; 664 | 665 | void fight(std::vector const & units) 666 | { 667 | for (auto u : units) 668 | u->attack(); 669 | } 670 | } 671 | 672 | namespace n712b 673 | { 674 | struct knight 675 | { 676 | void attack() { std::cout << "draw sword\n"; } 677 | }; 678 | 679 | struct mage 680 | { 681 | void attack() { std::cout << "spell magic curse\n"; } 682 | }; 683 | 684 | struct game_unit 685 | { 686 | virtual void attack() = 0; 687 | virtual ~game_unit() = default; 688 | }; 689 | 690 | template 691 | struct game_unit_wrapper : public game_unit 692 | { 693 | game_unit_wrapper(T& unit) : t(unit) {} 694 | 695 | void attack() override { t.attack(); } 696 | private: 697 | T& t; 698 | }; 699 | 700 | void fight(std::vector const& units) 701 | { 702 | for (auto u : units) 703 | u->attack(); 704 | } 705 | } 706 | 707 | namespace n712c 708 | { 709 | struct knight 710 | { 711 | void attack() { std::cout << "draw sword\n"; } 712 | }; 713 | 714 | struct mage 715 | { 716 | void attack() { std::cout << "spell magic curse\n"; } 717 | }; 718 | 719 | struct game 720 | { 721 | struct game_unit 722 | { 723 | virtual void attack() = 0; 724 | virtual ~game_unit() = default; 725 | }; 726 | 727 | template 728 | struct game_unit_wrapper : public game_unit 729 | { 730 | game_unit_wrapper(T& unit) : t(unit) {} 731 | 732 | void attack() override { t.attack(); } 733 | private: 734 | T& t; 735 | }; 736 | 737 | template 738 | void addUnit(T& unit) 739 | { 740 | units.push_back(std::make_unique>(unit)); 741 | } 742 | 743 | void fight() 744 | { 745 | for (auto& u : units) 746 | u->attack(); 747 | } 748 | private: 749 | std::vector> units; 750 | }; 751 | } 752 | 753 | namespace n712d 754 | { 755 | struct knight 756 | { 757 | void attack() { std::cout << "draw sword\n"; } 758 | }; 759 | 760 | struct mage 761 | { 762 | void attack() { std::cout << "spell magic curse\n"; } 763 | }; 764 | 765 | struct unit 766 | { 767 | template 768 | unit(T&& obj) : unit_(std::make_shared>(std::forward(obj))) {} 769 | 770 | void attack() 771 | { 772 | unit_->attack(); 773 | } 774 | 775 | struct unit_concept 776 | { 777 | virtual void attack() = 0; 778 | virtual ~unit_concept() = default; 779 | }; 780 | 781 | template 782 | struct unit_model : public unit_concept 783 | { 784 | unit_model(T& unit) : t(unit) {} 785 | 786 | void attack() override { t.attack(); } 787 | private: 788 | T& t; 789 | }; 790 | 791 | private: 792 | std::shared_ptr unit_; 793 | }; 794 | 795 | void fight(std::vector& units) 796 | { 797 | for (auto& u : units) 798 | u.attack(); 799 | } 800 | } 801 | 802 | namespace n712e 803 | { 804 | struct knight 805 | { 806 | void attack() { std::cout << "draw sword\n"; } 807 | }; 808 | 809 | struct mage 810 | { 811 | void attack() { std::cout << "spell magic curse\n"; } 812 | }; 813 | 814 | void fight_knight(void* k) 815 | { 816 | reinterpret_cast(k)->attack(); 817 | } 818 | 819 | void fight_mage(void* m) 820 | { 821 | reinterpret_cast(m)->attack(); 822 | } 823 | 824 | using fight_fn = void(*)(void*); 825 | 826 | void fight(std::vector> const& units) 827 | { 828 | for (auto& u : units) 829 | { 830 | u.second(u.first); 831 | } 832 | } 833 | } 834 | 835 | namespace n713 836 | { 837 | class async_bool 838 | { 839 | std::function check; 840 | public: 841 | async_bool() = delete; 842 | async_bool(std::function checkIt) 843 | : check(checkIt) 844 | { } 845 | 846 | async_bool(bool val) 847 | : check([val]() {return val; }) 848 | { } 849 | 850 | static async_bool yes() { return async_bool{ []() { return true; } }; } 851 | static async_bool no() { return async_bool{ []() { return false; } }; } 852 | 853 | bool operator&&(bool fore) const { return fore && check(); } 854 | bool operator!() const { return !check(); } 855 | operator bool() const { return check(); } 856 | }; 857 | } 858 | 859 | namespace n714 860 | { 861 | template 862 | struct typelist {}; 863 | 864 | struct empty_type {}; 865 | 866 | namespace detail 867 | { 868 | template 869 | struct length; 870 | 871 | template