├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── CMakePresets.json ├── README.md ├── book ├── C++20 STL Cookbook Leverage the Latest Features of the STL to Solve Real-World Pr.pdf ├── C++20 STL Cookbook 中文 标记版.pdf └── C++20 STL Cookbook 中文.pdf ├── src ├── 1.2格式化特化formatter.cpp ├── 1.3使用编译时constexpr vector和string.cpp ├── 1.4安全比较不同类型的整数cmp_less.cpp ├── 1.5三路比较运算符.cpp ├── 1.6查找特性测试宏.cpp ├── 1.7概念(concept)和约束(constraint)-创建更安全的模板.cpp ├── 1.8模块.cpp ├── 1.9视图.cpp ├── 10.2为path类特化formatter.cpp ├── 10.3使用带有路径的操作函数.cpp ├── 10.4列出目录中的文件.cpp ├── 10.5使用grep实用程序搜索目录和文件.cpp ├── 10.6使用regex和directory_iterator重命名文件.cpp ├── 10.7创建磁盘使用计数器.cpp ├── 2.2span类.cpp ├── 2.3结构化绑定.cpp ├── 2.4if&switch中的初始化.cpp ├── 2.5模板参数推导.cpp ├── 2.6编译期if.cpp ├── 3.10使用set进行输入和筛选.cpp ├── 3.11实现简单的RPN计算器与deque.cpp ├── 3.12使用map的词频计数器.cpp ├── 3.13找出含有相应长句的vector.cpp ├── 3.14使用multimap制作待办事项.cpp ├── 3.3使用擦除函数从容器中擦除项.cpp ├── 3.4常数时间内从未排序的向量中删除项.cpp ├── 3.5安全的访问vector元素.cpp ├── 3.6保持vector元素的顺序.cpp ├── 3.7高效的将元素插入到map中.cpp ├── 3.8高效的修改map项的键值.cpp ├── 3.9自定义键值的unordered_map.cpp ├── 4.10创建随机访问迭代器.cpp ├── 4.3创建可迭代范围.cpp ├── 4.4使迭代器与STL迭代器特性兼容.cpp ├── 4.5使用迭代器适配器填充STL容器.cpp ├── 4.6创建一个迭代器生成器.cpp ├── 4.7反向迭代器的反向适配器.cpp ├── 4.8用哨兵迭代未知长度的对象.cpp ├── 4.9构建zip迭代器适配器.cpp ├── 5.3用于作用域可重用代码.cpp ├── 5.4算法库中作为谓词.cpp ├── 5.5与function一起作为多态包装器.cpp ├── 5.6用递归连接lambda.cpp ├── 5.7将谓词与逻辑连接词连接起来.cpp ├── 5.8用相同的输入调用多个lambda.cpp ├── 5.9对跳转表使用映射lambda.cpp ├── 6.10合并已排序容器.cpp ├── 6.2基于迭代器的复制.cpp ├── 6.3将容器元素连接到以供字符串当中.cpp ├── 6.4sort排序容器元素.cpp ├── 6.5transform修改容器内容.cpp ├── 6.6查找特定项.cpp ├── 6.7将容器元素限制在clamp范围内.cpp ├── 6.8sample采集样本数据集.cpp ├── 6.9生成有序数据序列.cpp ├── 7.10使用文件输入初始化复杂结构体.cpp ├── 7.11使用char_traits.cpp ├── 7.12用正则表达式解析字符串.cpp ├── 7.3轻量字符串对象string_view.cpp ├── 7.4连接字符串.cpp ├── 7.5转换字符串.cpp ├── 7.6使用格式库格式化文本.cpp ├── 7.7删除字符串的空白.cpp ├── 7.8从用户输入中读取字符串.cpp ├── 7.9统计文件中的单词数.cpp ├── 8.10共享管理对象的成员.cpp ├── 8.11比较随机数引擎.cpp ├── 8.12比较随机数分布发生器.cpp ├── 8.2optional管理可选值.cpp ├── 8.3any保证类型安全.cpp ├── 8.4variant存储不同的类型.cpp ├── 8.5chrono的时间事件.cpp ├── 8.6对元组使用折叠表达式.cpp ├── 8.7unique_ptr管理已分配内存.cpp ├── 8.8shared_ptr的共享对象.cpp ├── 8.9对共享对象使用弱指针.cpp ├── 9.10实现多个生产者和消费者.cpp ├── 9.2休眠一定时间.cpp ├── 9.3thread实现并发.cpp ├── 9.4async实现并发.cpp ├── 9.5STL算法与执行策略.cpp ├── 9.6互斥锁和锁安全的共享数据.cpp ├── 9.7atomic共享标志和值.cpp ├── 9.8call_once初始化线程.cpp ├── 9.9condition_variable解决生产者-消费者问题.cpp ├── cities.txt ├── print.h ├── t.txt ├── test.ixx ├── test2.ixx ├── the-end.html └── the-raven.txt └── 交流 └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.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 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd 364 | 365 | # VS Code workspace settings 366 | .vscode 367 | 368 | # Obsidian workspace settings 369 | .obsidian -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.8) 2 | 3 | project (Test1) 4 | 5 | set(CMAKE_BUILD_TYPE Debug) 6 | 7 | set(CMAKE_CXX_STANDARD 23) 8 | 9 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) 10 | 11 | # 将源代码添加到此项目的可执行文件。 12 | add_executable (Test1 "src/10.7创建磁盘使用计数器.cpp") -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "configurePresets": [ 4 | { 5 | "name": "linux-debug", 6 | "displayName": "Linux Debug", 7 | "description": "面向适用于 Linux 的 Windows 子系统(WSL)或远程 Linux 系统。", 8 | "generator": "Ninja", 9 | "binaryDir": "${sourceDir}/out/build/${presetName}", 10 | "installDir": "${sourceDir}/out/install/${presetName}", 11 | "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }, 12 | "condition": { 13 | "type": "equals", 14 | "lhs": "${hostSystemName}", 15 | "rhs": "Linux" 16 | }, 17 | "vendor": { "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" } } 18 | }, 19 | { 20 | "name": "macos-debug", 21 | "displayName": "macOS Debug", 22 | "description": "以远程 macOS 系统为目标。", 23 | "generator": "Ninja", 24 | "binaryDir": "${sourceDir}/out/build/${presetName}", 25 | "installDir": "${sourceDir}/out/install/${presetName}", 26 | "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }, 27 | "condition": { 28 | "type": "equals", 29 | "lhs": "${hostSystemName}", 30 | "rhs": "Darwin" 31 | }, 32 | "vendor": { "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" } } 33 | }, 34 | { 35 | "name": "windows-base", 36 | "description": "面向具有 Visual Studio 开发环境的 Windows。", 37 | "hidden": true, 38 | "generator": "Visual Studio 17 2022", 39 | "binaryDir": "${sourceDir}/out/build/${presetName}", 40 | "installDir": "${sourceDir}/out/install/${presetName}", 41 | "cacheVariables": { 42 | "CMAKE_C_COMPILER": "cl.exe", 43 | "CMAKE_CXX_COMPILER": "cl.exe" 44 | }, 45 | "condition": { 46 | "type": "equals", 47 | "lhs": "${hostSystemName}", 48 | "rhs": "Windows" 49 | } 50 | }, 51 | { 52 | "name": "x64-debug", 53 | "displayName": "x64 Debug", 54 | "description": "使用 Visual Studio 开发环境定向到 Windows (64 位)。(Debug)", 55 | "inherits": "windows-base", 56 | "architecture": { 57 | "value": "x64", 58 | "strategy": "external" 59 | }, 60 | "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } 61 | }, 62 | { 63 | "name": "x64-release", 64 | "displayName": "x64 Release", 65 | "description": "使用 Visual Studio 开发环境定向到 Windows (64 位)。(RelWithDebInfo)", 66 | "inherits": "x64-debug", 67 | "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } 68 | }, 69 | { 70 | "name": "x86-debug", 71 | "displayName": "x86 Debug", 72 | "description": "用 Visual Studio 开发环境定向到 Windows (32 位)。(Debug)", 73 | "inherits": "windows-base", 74 | "architecture": { 75 | "value": "x86", 76 | "strategy": "external" 77 | }, 78 | "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } 79 | }, 80 | { 81 | "name": "x86-release", 82 | "displayName": "x86 Release", 83 | "description": "用 Visual Studio 开发环境定向到 Windows (32 位)。(RelWithDebInfo)", 84 | "inherits": "x86-debug", 85 | "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } 86 | } 87 | ] 88 | } -------------------------------------------------------------------------------- /book/C++20 STL Cookbook Leverage the Latest Features of the STL to Solve Real-World Pr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mq-b/Cpp20-STL-Cookbook-src/81526c59c8378a7ce80deb508b1d76bfd4aa8ebf/book/C++20 STL Cookbook Leverage the Latest Features of the STL to Solve Real-World Pr.pdf -------------------------------------------------------------------------------- /book/C++20 STL Cookbook 中文 标记版.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mq-b/Cpp20-STL-Cookbook-src/81526c59c8378a7ce80deb508b1d76bfd4aa8ebf/book/C++20 STL Cookbook 中文 标记版.pdf -------------------------------------------------------------------------------- /book/C++20 STL Cookbook 中文.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mq-b/Cpp20-STL-Cookbook-src/81526c59c8378a7ce80deb508b1d76bfd4aa8ebf/book/C++20 STL Cookbook 中文.pdf -------------------------------------------------------------------------------- /src/1.2格式化特化formatter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template < typename... Args> 6 | void print(const std::string_view fmt_str, Args&&... args) { 7 | auto fmt_args{ std::make_format_args(args...) }; 8 | std::string outstr{ std::vformat(fmt_str, fmt_args) }; 9 | fputs(outstr.c_str(), stdout); 10 | } 11 | 12 | struct Frac { 13 | int a, b; 14 | }; 15 | 16 | template<> 17 | struct std::formatter { 18 | template 19 | constexpr auto parse(ParseContext& ctx) { 20 | return ctx.begin(); 21 | } 22 | template 23 | auto format(const Frac& f, FormatContext& ctx) { 24 | return std::format_to(ctx.out(), "{0:d}/{1:d}", f.a, f.b); 25 | } 26 | }; 27 | 28 | int main() { 29 | Frac f{ 1,10 }; 30 | print("{}", f); 31 | } 32 | //格式化规则参见 https://zh.cppreference.com/w/cpp/utility/format/formatter 33 | //特化规则参见: https://zh.cppreference.com/w/cpp/named_req/Formatter -------------------------------------------------------------------------------- /src/1.3使用编译时constexpr vector和string.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | constexpr auto f() { 4 | std::vectorv{ 1,2,3 }; 5 | return v; 6 | } 7 | constexpr auto f2() { 8 | int* p = new int{ 10 }; 9 | //未delete解除分配 10 | return *p; 11 | } 12 | 13 | int main() { 14 | constexpr auto n = f().size();//√ 15 | //constexpr auto n2 = f()//error 16 | //constexpr auto n3 = f2()//error 17 | } 18 | 19 | //constexpr: https://zh.cppreference.com/w/cpp/language/constexpr -------------------------------------------------------------------------------- /src/1.4安全比较不同类型的整数cmp_less.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | constexpr bool cmp_less(T t, U u)noexcept { 5 | using UT = std::make_unsigned_t;//有符号类型到无符号类型的安全转换。 6 | using UU = std::make_unsigned_t; 7 | if constexpr (std::is_signed_v == std::is_signed_v) 8 | return t < u; 9 | else if constexpr (std::is_signed_v) 10 | return t < 0 ? true : UT(t) < u; 11 | else 12 | return u < 0 ? false : t < UU(u); 13 | } 14 | int main() { 15 | std::cout << std::boolalpha << (5u < -1) << '\n';//true 16 | std::cout << std::boolalpha << ::cmp_less(5u, 1) << '\n';//false 17 | std::cout << std::boolalpha << ::cmp_less(5u, 2u) << '\n';//false 18 | } 19 | 20 | //整数比较函数: https://zh.cppreference.com/w/cpp/utility/intcmp -------------------------------------------------------------------------------- /src/1.5三路比较运算符.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct X { 4 | int a{}; 5 | double b{}; 6 | char c{}; 7 | friend auto operator<=>(const X&,const X&) = default; 8 | }; 9 | 10 | struct Y { 11 | int a = 6; 12 | }; 13 | 14 | auto operator<=>(const Y& y, const Y& y2)noexcept->int {//自定义 15 | if (y.a == y2.a)return 0; 16 | if (y.a > y2.a)return 1; 17 | if (y.a < y2.a)return -1; 18 | } 19 | auto operator==(const Y& y, const Y& y2)noexcept->bool { 20 | return y.a == y2.a; 21 | } 22 | 23 | int main() { 24 | X x{ 10,1.2,'*' }; 25 | X x2{ 10,1,'*' }; 26 | x == x2; 27 | x <= x2; 28 | x != x2; 29 | x >= x2; 30 | Y y{ 1 }; 31 | Y y2{ 2 }; 32 | std::cout << (y <=> y2) << '\n'; //-1 33 | std::cout << std::boolalpha << (y > y2) << '\n';//false 34 | std::cout << std::boolalpha << (y < y2) << '\n';//true 35 | std::cout << std::boolalpha << (y != y2) << '\n';//true 36 | } 37 | 38 | //三路比较运算符: https://zh.cppreference.com/w/cpp/language/operator_comparison 39 | //默认比较: https://zh.cppreference.com/w/cpp/language/default_comparisons -------------------------------------------------------------------------------- /src/1.6查找特性测试宏.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef __cpp_lib_three_way_comparison 5 | # include 6 | #else 7 | # error 没有与之对应的头文件 8 | #endif // __cpp_lib_three_way_comparison 9 | 10 | #ifdef __cpp_lib_format 11 | # include 12 | #else 13 | # error 没有与之对应的头文件 14 | #endif // __cpp_lib_three_way_comparison 15 | 16 | #if __has_include()//检查能不能找到这个文件,如果能找到这个宏就返回1 17 | # include 18 | #endif 19 | 20 | int main() { 21 | std::cout << __cpp_lib_three_way_comparison << '\n';//为 201907,意味着其在 2019 年 7 月采纳。 22 | std::cout << __cpp_lib_format << '\n'; //为 202110,意味着其在 2021 年 10 月采纳。 23 | } 24 | 25 | //库功能性测试宏: https://zh.cppreference.com/w/cpp/utility/feature_test 26 | //诊断指令: https://zh.cppreference.com/w/cpp/preprocessor/error -------------------------------------------------------------------------------- /src/1.7概念(concept)和约束(constraint)-创建更安全的模板.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | void f(T t){} 5 | 6 | template 7 | requires std::integral || std::is_pointer_v 8 | struct X { 9 | 10 | }; 11 | 12 | template 13 | requires std::is_integral_v 14 | T n{}; 15 | 16 | template 17 | concept love = std::is_integral_v && (std::is_same_v || std::is_same_v); 18 | 19 | void f2(love auto){} 20 | 21 | int main() { 22 | f(1); 23 | f('*'); 24 | //f(1.2); 25 | Xx; 26 | //Xx2; 27 | Xx3; 28 | n = 3; 29 | //n; 30 | std::cout << n << '\n'; 31 | f2(1); 32 | f2(1u); 33 | //f2(1l); 34 | } 35 | 36 | //Requires表达式 https://zh.cppreference.com/w/cpp/language/requires 37 | //约束与概念 https://zh.cppreference.com/w/cpp/language/constraints -------------------------------------------------------------------------------- /src/1.8模块.cpp: -------------------------------------------------------------------------------- 1 | import test; 2 | 3 | int main() { 4 | /*int n[]{ 5 | #include"t.txt" 6 | }; 7 | for (auto i : n) { 8 | std::cout << i << ' '; 9 | }*/ 10 | 11 | std::cout << mylib::add(1, 2) << '\n'; 12 | //mylib::print("*"); 13 | t(); 14 | } 15 | 16 | //模块: https://zh.cppreference.com/w/cpp/language/modules 17 | //编译设置:add_executable (Test1 "src/1.8模块.cpp" "src/test.ixx" "src/test2.ixx") -------------------------------------------------------------------------------- /src/1.9视图.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | namespace stdv = std::views; 5 | namespace stdr = std::ranges; 6 | 7 | void print(stdr::range auto v) { 8 | for (const auto& i : v)std::cout << i << ' '; 9 | endl(std::cout); 10 | } 11 | 12 | int main() { 13 | std::vector nums{ 1,2,3,4,5,6,7,8,9,10 }; 14 | auto ret = nums | stdv::take(5) | stdv::reverse; 15 | print(ret); 16 | auto ret2 = nums | stdv::filter([](int i) {return i > 6; }); 17 | print(ret2); 18 | auto ret3 = nums | stdv::transform([](int i) {return i * i; }); 19 | print(ret3); 20 | print(nums);//视图是不会改变原来的数据的 21 | 22 | std::vectorstrs{ "🐴","🐭","🥵","🤣" }; 23 | auto ret4 = strs | stdv::reverse; 24 | print(ret4); 25 | 26 | auto ret5 = nums | stdv::filter([](int i) {return i % 2 != 0; }) | stdv::transform([](int i) {return i * 2; }); 27 | print(ret5); 28 | 29 | auto nums_ = stdv::iota(1, 10); 30 | print(nums_); 31 | 32 | auto rnums = stdv::iota(1) | stdv::take(200); 33 | print(rnums); 34 | 35 | stdr::copy(strs | stdv::reverse | stdv::drop(2), std::ostream_iterator(std::cout," ")); 36 | } 37 | 38 | //范围库: https://zh.cppreference.com/w/cpp/ranges -------------------------------------------------------------------------------- /src/10.2为path类特化formatter.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | namespace fs = std::filesystem; 4 | 5 | //template<> 6 | //struct std::formatter { 7 | // template 8 | // constexpr auto parse(ParseContext& ctx) { 9 | // return ctx.begin(); 10 | // } 11 | // template 12 | // auto format(const fs::path& p, FormatContext& ctx) { 13 | // return std::format_to(ctx.out(), "{}", p.string()); 14 | // } 15 | //};//我们将其放入print.h中,以便后面使用 16 | 17 | int main(const int argc,const char**argv) { 18 | if (argc != 2) { 19 | fs::path fn{ argv[0] }; 20 | print("usage: {} \n", fn.filename()); 21 | return 0; 22 | } 23 | fs::path dir{ argv[1] }; 24 | if (!fs::exists(dir)) { 25 | print("path: {} does not exist\n", dir); 26 | return 1; 27 | } 28 | print("path: {}\n", dir);//普通的使用特化格式化打印 29 | print("filename: {}\n", dir.filename());//文件名 30 | print("cannonical: {}\n", fs::canonical(dir));//绝对路径 31 | 32 | fs::path p{ "~/include/bwprint.h" }; 33 | print("{}\n", p);//普通格式化打印 34 | print("{}\n", p.stem());//返回通用格式路径所标识的文件名,剥去其扩展名 35 | print("{}\n", p.extension());//返回文件扩展名 36 | print("{}\n", p.filename());//返回文件名(包含后缀) 37 | print("{}\n", p.parent_path());//返回到亲目录的路径。 38 | } -------------------------------------------------------------------------------- /src/10.3使用带有路径的操作函数.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include"print.h" 3 | #include 4 | 5 | int main() { 6 | fs::path p = "E:cl.exe"; 7 | print("current_path: {}\n", fs::current_path()); 8 | print("absolute(p): {}\n", fs::absolute(p)); 9 | print("append: {}\n", fs::path{ "tetdir" } /= "foo.txt"); 10 | print("canoical: {}\n", fs::canonical(fs::path{ "." }/="1..txt")); 11 | print("equivalent: {}\n", fs::equivalent("1..txt", "E:/自制视频教程/《C++20 STL Cookbook》2023/src/bin/Debug/1..txt")); 12 | 13 | try { 14 | fs::path p{ "1..txt" }; 15 | print("p: {}\n", p); 16 | (void)fs::equivalent("1..txt", "debug/1.txt"); 17 | } 18 | catch (const fs::filesystem_error& e) { 19 | print("{}\n", e.what()); 20 | print("parth1: {}\n", e.path1()); 21 | print("parth2: {}\n", e.path2()); 22 | } 23 | 24 | fs::path p2{ "1..txt" }; 25 | std::error_code e; 26 | print("canonical: {}\n", fs::canonical(p2 / "foo", e)); 27 | print("error: {}\n", e.message());//打印错误 28 | } -------------------------------------------------------------------------------- /src/10.4列出目录中的文件.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include"print.h" 3 | #include 4 | using de = fs::directory_entry; 5 | 6 | std::string strlower(std::string s) { 7 | auto char_lower = [](const char& c)->char { 8 | if (c >= 'A' && c <= 'Z')return c + 32; 9 | else return c; 10 | }; 11 | std::transform(s.begin(), s.end(), s.begin(), char_lower); 12 | return s; 13 | } 14 | bool dircmp_lc(const de& lhs, const de& rhs) { 15 | const auto lhstr{ lhs.path().string() }; 16 | const auto rhstr{ rhs.path().string() }; 17 | return strlower(lhstr) < strlower(rhstr); 18 | } 19 | char type_char(const fs::file_status& fstat) { 20 | if (fs::is_symlink(fstat))return 'l'; 21 | else if (fs::is_directory(fstat))return 'd'; 22 | else if (fs::is_character_file(fstat))return 'c'; 23 | else if (fs::is_block_file(fstat))return 'b'; 24 | else if (fs::is_fifo(fstat))return 'p'; 25 | else if (fs::is_socket(fstat))return 's'; 26 | else if (fs::is_other(fstat))return 'o'; 27 | else if (fs::is_regular_file(fstat))return '-'; 28 | return '?'; 29 | } 30 | std::string rwx(const fs::perms& p) { 31 | using fs::perms; 32 | auto bit2char = [&](perms bit, char c) { 33 | return (p & bit) == perms::none ? '-' : c; 34 | }; 35 | return { bit2char(perms::owner_read,'r'), 36 | bit2char(perms::owner_write,'w'), 37 | bit2char(perms::owner_exec,'x'), 38 | bit2char(perms::group_read,'r'), 39 | bit2char(perms::group_write,'w'), 40 | bit2char(perms::group_exec,'x'), 41 | bit2char(perms::others_read,'r'), 42 | bit2char(perms::others_write,'w'), 43 | bit2char(perms::others_exec,'x'), 44 | }; 45 | } 46 | std::string size_string(const uintmax_t fsize) { 47 | constexpr const uintmax_t kilo{ 1024 }; 48 | constexpr const uintmax_t mega{ kilo * 1024 }; 49 | constexpr const uintmax_t giga{ mega * kilo }; 50 | std::string s; 51 | if (fsize >= giga)return std::format("{}{}", fsize / giga, 'G'); 52 | else if (fsize >= mega)return std::format("{}{}", fsize / mega, 'M'); 53 | else if (fsize >= kilo)return std::format("{}{}", fsize / kilo, 'K'); 54 | else return std::format("{}B", fsize); 55 | } 56 | std::string time_string(const fs::directory_entry& dir) { 57 | auto file_time{ dir.last_write_time() }; 58 | auto t =std::chrono::current_zone()->to_local(std::chrono::clock_cast(file_time)); 59 | auto str =std::format("{}", t); 60 | auto index = str.find('.'); 61 | str.replace(index, str.size(), ""); 62 | return str; 63 | } 64 | void print_dir(const de& dir) { 65 | using fs::perms; 66 | const auto fpath{ dir.path() };//获取路径 67 | const auto fstat{ dir.symlink_status() };//获取文件状态 68 | const auto fperm{ fstat.permissions() };//获取文件权限 69 | const uintmax_t fsize{ fs::is_regular_file(fstat) ? fs::file_size(fpath) : 0 }; 70 | const auto fn{ fpath.filename() }; 71 | const auto permstr{ type_char(fstat) + rwx(fperm) }; 72 | const std::string timestr{ time_string(dir) }; 73 | 74 | std::string suffix{}; 75 | if (fs::is_symlink(fstat)) { 76 | suffix = "-> "; 77 | suffix += fs::read_symlink(fpath).string(); 78 | } 79 | else if (fs::is_directory(fstat))suffix = "/";//如果是目录就加杠 80 | else if ((fperm & perms::owner_exec) != perms::none) { 81 | suffix = "*";//如果是可执行可查找文件就加*,权限参见owner_exec 82 | } 83 | std::cout<6} {} {}{}\n", permstr, size_string(fsize),timestr,fn, suffix); 84 | } 85 | 86 | int main() { 87 | //fs::create_directories("sandbox/subdir"); 88 | //fs::create_directory_symlink("sandbox/subdir", "include"); 89 | const fs::path fp{ "." }; 90 | std::vectorentries{}; 91 | if (fs::is_directory(fp)) { 92 | for (const auto& de : fs::directory_iterator{ fp }) { 93 | entries.emplace_back(de); 94 | } 95 | 96 | std::sort(entries.begin(), entries.end(),dircmp_lc); 97 | for (const auto& e : entries) { 98 | print_dir(e); 99 | } 100 | } 101 | else { 102 | std::cout< 3 | #include 4 | using de = fs::directory_entry; 5 | using rdit = fs::recursive_directory_iterator; 6 | using rdit = fs::recursive_directory_iterator; 7 | using match_v = std::vector>; 8 | 9 | //从文件中获取正则表达式匹配 10 | match_v matches(const fs::path& fpath, const std::regex& re) { 11 | match_v matches{}; 12 | std::ifstream instrm{ fpath.string() ,std::ios_base::in}; 13 | std::string s; 14 | for (size_t lineo{ 1 }; std::getline(instrm, s); ++lineo) { 15 | if (std::regex_search(s.begin(), s.end(), re)) {//要是正则和字符串匹配则返回true 16 | matches.emplace_back(lineo, s);//插入第几行和匹配的字符串 17 | } 18 | } 19 | return matches; 20 | } 21 | size_t pmatches(const std::regex& re, const fs::path epath, const fs::path& search_path) { 22 | fs::path target{ epath }; 23 | auto regmatches{ matches(epath,re) }; 24 | auto matchcount{ regmatches.size()}; 25 | if (!matchcount)return 0; 26 | if (!(search_path == epath)) { 27 | target = epath.lexically_relative(search_path);//将target转换路径到相对路径 28 | } 29 | for (const auto& [lineno, line] : regmatches) { 30 | std::cout << std::format("{} {}: {}\n", target, lineno, line); 31 | } 32 | return regmatches.size(); 33 | } 34 | 35 | int main(const int argc,const char**argv) { 36 | const char* arg_pat{};//命令行中的正则表达式模式 37 | std::regex re{};//正则表达式对象 38 | fs::path search_path{};//命令行搜索路径是参数 39 | size_t matchcount{};//计数匹配的行 40 | if (argc < 2) { 41 | auto cmdname{ fs::path(argv[0]).filename() }; 42 | std::cout << cmdname << '\n'; 43 | return 1; 44 | } 45 | 46 | arg_pat = argv[1]; 47 | try { 48 | re = std::regex(arg_pat, std::regex_constants::icase); 49 | }catch (std::regex_error& e) { 50 | std::cout << std::format("{}: {}\n", e.what(), arg_pat); 51 | return 1; 52 | } 53 | 54 | if (argc == 2) { 55 | search_path = "."; 56 | for (const auto& entry : rdit{ search_path }) { 57 | const auto& epath{ entry.path() }; 58 | matchcount += pmatches(re, epath, search_path); 59 | } 60 | } 61 | int count{ argc - 2 }; 62 | while (count-- > 0) { 63 | fs::path p{ argv[count + 2] }; 64 | if (!fs::exists(p)) { 65 | std::cout << std::format("not found: {}\n", p); 66 | continue; 67 | } 68 | if (fs::is_directory(p)) { 69 | for (const auto& entry : rdit{ p }) { 70 | const auto epath{ entry.path() }; 71 | matchcount += pmatches(re, epath, p); 72 | } 73 | }else { 74 | matchcount += pmatches(re, p, p); 75 | } 76 | } 77 | std::cout << std::format("found {} matches\n", matchcount); 78 | } -------------------------------------------------------------------------------- /src/10.6使用regex和directory_iterator重命名文件.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | using dit = fs::directory_iterator; 4 | using pat_v = std::vector>; 5 | 6 | std::string replace_str(std::string s, const pat_v& replacements) { 7 | for (const auto& [pattern, repl] : replacements){ 8 | s = std::regex_replace(s, pattern, repl);//第一个参数是传入字符串,第二个是正则对象用于匹配,第三个是替换匹配上的字符串 9 | } 10 | return s; 11 | } 12 | 13 | int main(const int argc,const char**argv) { 14 | pat_v patterns{}; 15 | if (argc < 3 || argc % 2 != 1) { 16 | fs::path cmdname{ fs::path(argv[0]).filename() }; 17 | std::cout << std::format("usage: {} [regex replacement] ...\n", cmdname); 18 | return 1; 19 | }//argc默认就有一个,我们的要求是一个字符串后面跟一个替换,那么算上那个1就是必须是奇数,所以如果不满足就退出 20 | 21 | for (int i{ 1 }; i < argc; i += 2) { 22 | patterns.emplace_back(argv[i], argv[i + 1]); 23 | } 24 | 25 | for (const auto& entry : dit{ fs::current_path() }) { 26 | fs::path fpath{ entry.path() }; 27 | std::string rname{replace_str(fpath.filename().string(),patterns)}; 28 | if (fpath.filename().string() != rname) { 29 | fs::path rpath{ fpath }; 30 | rpath.replace_filename(rname);//更改rpath的路径文件名 31 | 32 | fs::rename(fpath, rpath);//这个函数调用才是真正的更改文件名,它不修改传入的两个path对象,而是真正的修改文件名 33 | std::cout << std::format("{} -> {}\n", fpath.filename(), rpath.filename());//fpath是原始,rpath是更改之后 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/10.7创建磁盘使用计数器.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | using dit = fs::directory_iterator; 3 | using de = fs::directory_entry; 4 | 5 | std::string make_commas(const unsigned long num) {//把数字串中间添加逗号,三位一个逗号分隔 6 | std::string s{ std::to_string(num) }; 7 | for (int l = s.length() - 3; l > 0; l -= 3) 8 | s.insert(l, ","); 9 | return s; 10 | } 11 | std::string strlower(std::string s) {//全部小写 12 | auto char_lower = [](const char& c)->char { 13 | if (c >= 'A' && c <= 'Z')return c + 32; 14 | else return c; 15 | }; 16 | std::transform(s.begin(), s.end(), s.begin(), char_lower); 17 | return s; 18 | } 19 | bool dircmp_lc(const de& lhs, const de& rhs) { 20 | const auto lhstr{ lhs.path().string() }; 21 | const auto rhstr{ rhs.path().string() }; 22 | return strlower(lhstr) < strlower(rhstr); 23 | } 24 | std::string size_string(const uintmax_t fsize) { 25 | constexpr const uintmax_t kilo{ 1024 }; 26 | constexpr const uintmax_t mega{ kilo * 1024 }; 27 | constexpr const uintmax_t giga{ mega * kilo }; 28 | std::string s; 29 | if (fsize >= giga)return std::format("{}{}", fsize / giga, 'G'); 30 | else if (fsize >= mega)return std::format("{}{}", fsize / mega, 'M'); 31 | else if (fsize >= kilo)return std::format("{}{}", fsize / kilo, 'K'); 32 | else return std::format("{}B", fsize); 33 | } 34 | uintmax_t entry_size(const fs::path& p) { 35 | if (fs::is_regular_file(p))return fs::file_size(p); 36 | uintmax_t accum{}; 37 | if (fs::is_directory(p) && !fs::is_symlink(p)) { 38 | for (auto& e : dit{ p }) { 39 | accum += entry_size(e.path()); 40 | } 41 | } 42 | return accum; 43 | } 44 | 45 | int main(const int argc,const char**argv) { 46 | auto dir{ argc > 1 ? fs::path(argv[1]) : fs::current_path() }; 47 | std::vectorentries{}; 48 | uintmax_t accum{};//目录文件总字节大小 49 | if (!fs::exists(dir)) { 50 | std::cout << std::format("path {} does not exist\n", dir); 51 | return 1; 52 | } 53 | if (!fs::is_directory(dir)) { 54 | std::cout << std::format("{} is not a directory\n", dir); 55 | return 1; 56 | } 57 | std::cout << std::format("{}:\n", fs::absolute(dir)); 58 | 59 | for (const auto& e : dit{ dir }) { 60 | entries.emplace_back(e.path()); 61 | } 62 | std::sort(entries.begin(), entries.end(), dircmp_lc); 63 | 64 | for (const auto& e : entries) { 65 | fs::path p{ e }; 66 | uintmax_t esize{ entry_size(p) }; 67 | std::string dir_flag{}; 68 | accum += esize; 69 | if (fs::is_directory(p) && !fs::is_symlink(p))dir_flag = " *"; 70 | std::cout << std::format("{:>5} {} {}\n", size_string(esize), p.filename(), dir_flag); 71 | } 72 | std::cout << std::format("{:->25}\n", ""); 73 | std::cout << std::format("total bytes: {} ({})\n", make_commas(accum), size_string(accum)); 74 | } -------------------------------------------------------------------------------- /src/2.2span类.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template < typename... Args> 6 | void print(const std::string_view fmt_str, Args&&... args) { 7 | auto fmt_args{ std::make_format_args(args...) }; 8 | std::string outstr{ std::vformat(fmt_str, fmt_args) }; 9 | fputs(outstr.c_str(), stdout); 10 | } 11 | 12 | template 13 | void pspan(std::spans) { 14 | print("number of elemnts: {}\n", s.size()); 15 | print("size of span: {}\n", s.size_bytes()); 16 | for (auto i : s)print("{} ", i); 17 | endl(std::cout); 18 | } 19 | 20 | int main() { 21 | int array[]{ 1,2,3,4,5,6 }; 22 | pspan(array); 23 | } 24 | 25 | //span文档: https://zh.cppreference.com/w/cpp/container/span 26 | //span简单实现: https://github.com/13870517674/c-plus-plus/blob/master/src/lib/span.hpp -------------------------------------------------------------------------------- /src/2.3结构化绑定.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template < typename... Args> 8 | void print(const std::string_view fmt_str, Args&&... args) { 9 | auto fmt_args{ std::make_format_args(args...) }; 10 | std::string outstr{ std::vformat(fmt_str, fmt_args) }; 11 | fputs(outstr.c_str(), stdout); 12 | } 13 | 14 | struct X { int a; double b; std::string str; }; 15 | 16 | auto f()->std::tuple { 17 | return { 1,2 }; 18 | } 19 | 20 | int main() { 21 | int array[]{ 1,2,3,4,5 }; 22 | auto& [a, b, c, d, e] = array; 23 | print("{} {} {} {} {}\n", a, b, c, d, e); 24 | a = 10; 25 | print("{}\n", array[0]); 26 | 27 | std::array arr{ '*','a','b','&' }; 28 | auto [a_, b_, c_, d_] = arr; 29 | print("{} {} {} {}\n", a_, b_, c_, d_); 30 | 31 | std::tupletu{ 10,3.14,"🥵" }; 32 | auto [t1, t2, t3] = tu; 33 | print("{} {} {}\n", t1, t2, t3); 34 | 35 | X x{ 1,5.2,"🤣" }; 36 | auto [x1, x2, x3] = x; 37 | print("{} {} {}\n", x1, x2, x3); 38 | 39 | const std::array arr2{ 1,2 }; 40 | //auto& [c_arr1, c_arr2] = arr2; 41 | //c_arr1 = 10;//error 42 | 43 | auto [f1, f2] = f(); 44 | print("{} {}\n", f1, f2); 45 | 46 | std::mapMap{ {1,"*"},{2,"😘"} }; 47 | for (const auto& [m_a, m_b] : Map) { 48 | print("{} {}\n", m_a, m_b); 49 | } 50 | } -------------------------------------------------------------------------------- /src/2.4if&switch中的初始化.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | std::mutex m; 6 | bool flag = true; 7 | 8 | void f(int n) { 9 | if (std::lock_guard lg{ m }; flag) { 10 | print("乐\t"); 11 | print("🤣🤣🤣\n"); 12 | } 13 | } 14 | 15 | void t() { 16 | if (auto flag = [](int n) {return n * n; }(10); flag != 0) { 17 | print("🐴🐴🐴\n"); 18 | } 19 | } 20 | 21 | void t2() { 22 | switch (char c = getchar();c) 23 | { 24 | case 'a': 25 | print("a\n"); 26 | break; 27 | case 'b': 28 | print("b\n"); 29 | break; 30 | case 'c': 31 | print("c\n"); 32 | break; 33 | case 'd': 34 | print("d\n"); 35 | break; 36 | default: 37 | print("error\n"); 38 | break; 39 | } 40 | } 41 | 42 | int main() { 43 | for (int i = 0; i < 10; i++) { 44 | std::jthread t{ f,0 }; 45 | std::jthread t2{ f,0 }; 46 | } 47 | t(); 48 | t2(); 49 | } -------------------------------------------------------------------------------- /src/2.5模板参数推导.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | 3 | using namespace std::string_literals; 4 | 5 | template 6 | struct X { 7 | T v{}; 8 | template 9 | X(Args&&...args) :v{ (args + ...) } {} 10 | }; 11 | 12 | template 13 | X(Ts...ts) -> X>; 14 | 15 | int main() { 16 | X x("10","🤣"s); 17 | print("{}\n", x.v); 18 | } -------------------------------------------------------------------------------- /src/2.6编译期if.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | 3 | template 4 | auto f(const T& v) { 5 | if constexpr (std::is_pointer_v) 6 | print("pointer\n"); 7 | else 8 | print("no pointer\n"); 9 | } 10 | 11 | template 12 | void show(T t, Args&&...args) { 13 | print("{}\t",t); 14 | if constexpr (sizeof...(args)) { 15 | show(args...); 16 | } 17 | } 18 | 19 | int main() { 20 | int* p{}; 21 | f(p); 22 | f(1); 23 | show(5,314, "🤣", '*'); 24 | print("\n"); 25 | } -------------------------------------------------------------------------------- /src/3.10使用set进行输入和筛选.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::setsets; 8 | std::copy(std::istream_iterator{std::cin}, {}, 9 | std::inserter(sets, sets.end())); 10 | print(sets); 11 | } -------------------------------------------------------------------------------- /src/3.11实现简单的RPN计算器与deque.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | class RPN { 6 | std::dequedeq_{}; 7 | constexpr static double zero_{ 0.0 }; 8 | constexpr static double inf_{ std::numeric_limits::infinity() }; 9 | 10 | bool is_numeric(const std::string str) { 11 | for (const auto& i:str) { 12 | if (i != '.' && !std::isdigit(i)) 13 | return false; 14 | } 15 | return true; 16 | } 17 | 18 | std::pairpop_get2() { 19 | if (deq_.size() < 2)return { zero_,zero_ }; 20 | double v1{ deq_.front() }; 21 | deq_.pop_front(); 22 | double v2{ deq_.front() }; 23 | deq_.pop_front(); 24 | return { v2,v1 }; 25 | } 26 | 27 | double optor(const std::string op) { 28 | std::mapopmap{ 29 | {"+",[](double l,double r) {return l + r; }}, 30 | {"-",[](double l,double r) {return l - r; }}, 31 | {"*",[](double l,double r) {return l * r; }}, 32 | {"/",[](double l,double r) {return l / r; }}, 33 | {"^",[](double l,double r) {return std::pow(l,r); }}, 34 | {"%",[](double l,double r) {return std::fmod(l,r); }} 35 | }; 36 | if (opmap.find(op) == opmap.end())return zero_; 37 | auto [l, r] = pop_get2(); 38 | if (op == "/" && r == zero_)deq_.push_front(inf_); 39 | else deq_.push_front(opmap.at(op)(l, r)); 40 | return deq_.front(); 41 | } 42 | 43 | public: 44 | double op(const std::string& s) { 45 | if (is_numeric(s)) { 46 | double v{ std::stod(s) }; 47 | deq_.push_front(v); 48 | return v; 49 | } 50 | else return optor(s); 51 | } 52 | 53 | void clear() { 54 | deq_.clear(); 55 | } 56 | 57 | std::string get_stack_string()const { 58 | std::string s{}; 59 | for (const auto& v : deq_) { 60 | s += std::format("{} ", v); 61 | } 62 | return s; 63 | } 64 | }; 65 | 66 | int main() { 67 | RPN rpn; 68 | for (std::string o{}; std::cin >> o;) { 69 | rpn.op(o); 70 | auto stack_str{ rpn.get_stack_string() }; 71 | print("{}: {}\n", o, stack_str); 72 | } 73 | } -------------------------------------------------------------------------------- /src/3.12使用map的词频计数器.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | 6 | namespace stdr = std::ranges; 7 | namespace regex_constants = std::regex_constants; 8 | namespace bw { constexpr const char* re{ "(\\w+)" }; } 9 | 10 | int main() { 11 | std::mapwordmap{}; 12 | std::vector>wordvec{}; 13 | std::regex word_re(bw::re); 14 | size_t total_words{}; 15 | 16 | for (std::string s{}; std::cin >> s;) { 17 | auto words_begin{ std::sregex_iterator(s.begin(),s.end(),word_re) }; 18 | auto words_end{ std::sregex_iterator() }; 19 | for (auto r_it{ words_begin }; r_it != words_end; ++r_it) { 20 | std::smatch match{ *r_it };//字符串匹配类 21 | auto word_str{ match.str() };//得到输入的单词 22 | stdr::transform(word_str, word_str.begin(), [](uint8_t c) {return tolower(c); });//将字母全部大写 23 | auto [map_it, result] = wordmap.try_emplace(word_str, 0);//插入到map中,map的键不会有重复,自动去重 24 | auto& [w, count] = *map_it; 25 | ++total_words; 26 | ++count;//增加单词计数 27 | } 28 | } 29 | auto unique_words = wordmap.size(); 30 | wordvec.reserve(unique_words); 31 | stdr::move(wordmap, std::back_inserter(wordvec)); 32 | stdr::sort(wordvec, [](const auto& a, const auto& b) { 33 | return (a.second != b.second) ? (a.second > b.second) : (a.first < b.first); 34 | }); 35 | 36 | print("unique word count: {}\n", total_words);//总共的单词个数 37 | print("unqiue word count: {}\n", unique_words);//去除重复之后的 38 | for (int limit{ 20 }; auto & [w, count]:wordvec) { 39 | print("{}: {}\n", count, w); 40 | //if (--limit == 0)break; 41 | } 42 | } -------------------------------------------------------------------------------- /src/3.13找出含有相应长句的vector.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | namespace stdr = std::ranges; 7 | 8 | bool is_eos(const std::string_view& str) { 9 | constexpr const char* end_punct{ ".!?" }; 10 | for (auto c : str) { 11 | if (strchr(end_punct, c) != nullptr) 12 | return true; 13 | } 14 | return false; 15 | } 16 | 17 | int main() { 18 | std::vector>vv_sentences{ std::vector{} }; 19 | for (std::string s{}; std::cin >> s;) { 20 | vv_sentences.back().emplace_back(s); 21 | if (is_eos(s)) { 22 | vv_sentences.emplace_back(std::vector{}); 23 | } 24 | } 25 | 26 | if (vv_sentences.back().empty())vv_sentences.pop_back(); 27 | stdr::sort(vv_sentences, [](const auto& l, const auto& r) { 28 | return l.size() > r.size(); 29 | }); 30 | 31 | for (const auto& v : vv_sentences) { 32 | size_t size = v.size(); 33 | print("{}: ", size); 34 | for (const auto& s : v) { 35 | print("{} ", s); 36 | } 37 | print("\n"); 38 | } 39 | print("\n"); 40 | } -------------------------------------------------------------------------------- /src/3.14使用multimap制作待办事项.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | int main() { 5 | std::multimaptodo{ 6 | {1,"🤣"}, 7 | {2,"🥵"}, 8 | {3,"🐴"}, 9 | {4,"😘"} 10 | }; 11 | rprint(todo); 12 | } -------------------------------------------------------------------------------- /src/3.3使用擦除函数从容器中擦除项.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | template 6 | void remove_value(Tc& c, const Tv& v) {//C++20之前的做法 7 | //std::remove将和传入元素相同的元素移动放到末尾,并返回迭代器位置,还有一个std::remove_if的版本 8 | auto remove_it = std::remove(c.begin(), c.end(), v);//remove_it是首个需要被删除元素的位置 9 | c.erase(remove_it, c.end());//删除remove_it到end()这个范围的元素 10 | } 11 | 12 | int main() { 13 | std::vector v{ 1,2,3,4,5 }; 14 | print(v); 15 | ::remove_value(v, 1); 16 | print(v); 17 | std::erase(v,5);//C++20起,功能和remove_value()相同 18 | print(v); 19 | std::erase_if(v, [](int i) {return i % 2 != 0; });//第二个版本 20 | print(v); 21 | 22 | std::list list{ 1,2,3,4,5,6,7,8,9,10 }; 23 | std::erase(list, 5); 24 | std::erase_if(list, [](int i) {return i % 2 == 0; }); 25 | print(list); 26 | 27 | std::map map{ {1,"🤣"},{2,"🥵"},{3,"🐴"},{4,"🐭"} }; 28 | print(map); 29 | std::erase_if(map, [](auto& i) { 30 | const auto& [k, v] = i; 31 | return v == "🥵"; 32 | }); 33 | print(map); 34 | } -------------------------------------------------------------------------------- /src/3.4常数时间内从未排序的向量中删除项.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | namespace stdr = std::ranges; 5 | 6 | //使用下标的版本 7 | template 8 | void quick_delete(T& v, size_t idx) { 9 | if (idx < v.size()) { 10 | v[idx] = std::move(v.back()); 11 | v.pop_back(); 12 | } 13 | } 14 | //使用迭代器的版本 15 | template 16 | void quick_delete(T& v, typename T::iterator it) { 17 | if (it < v.end()) { 18 | *it = std::move(v.back()); 19 | v.pop_back(); 20 | } 21 | } 22 | //若 vector 中项目的顺序不重要,就可以优化这个过程,使其花费 O(1)(常数) 时间 23 | //做法很简单,将传入的要删除的迭代器或索引赋值为末尾元素的值,然后将末尾元素删除,就完成了,但是没有顺序 24 | 25 | int main() { 26 | std::vector v{ 1,2,3,4,5 }; 27 | print(v); 28 | auto it = stdr::find(v, 3); 29 | quick_delete(v, it); 30 | print(v);//顺序不对,正常现象 31 | 32 | quick_delete(v, 2); 33 | print(v); 34 | } -------------------------------------------------------------------------------- /src/3.5安全的访问vector元素.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | void test1() { 5 | std::vector v{ 1,2,3,4,5 }; 6 | v[5] = 2001;//写入非法内存,访问也是越界 7 | auto& i = v[5];//引用了错误的内存 8 | print("{}\n", i);//可能发生错误,不保证 9 | } 10 | 11 | void test2()try { 12 | std::vector v{ 1,2,3,4,5 }; 13 | auto& i = v.at(5); 14 | print("{}\n", i); 15 | } 16 | catch (std::exception& e) { 17 | print("{}\n", e.what()); 18 | } 19 | 20 | void test3()try { 21 | std::vector v{ 1,2,3,4,5 }; 22 | auto& i = v[5]; 23 | print("{}\n", i); 24 | } 25 | catch (std::exception& e) { 26 | print("{}\n", e.what()); 27 | } 28 | int main() { 29 | //test1();//error 30 | test2(); 31 | //test3();//error 32 | } -------------------------------------------------------------------------------- /src/3.6保持vector元素的顺序.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | using Vstr = std::vector; 6 | namespace stdr = std::ranges; 7 | 8 | void psorted(stdr::range auto&& v) { 9 | if (stdr::is_sorted(v)) 10 | print("sorted: "); 11 | else 12 | print("unsorted: "); 13 | print(v); 14 | } 15 | 16 | void insert_sorted(Vstr& v, const std::string& s) { 17 | //lower_bound() 算法查找不小于实参的第一个元素的迭代器 18 | const auto pos{ stdr::lower_bound(v,s) }; 19 | v.insert(pos, s);//使用 lower_bound() 返回的迭代器在正确的位置插入一个元素 20 | } 21 | 22 | template 23 | void insert_sorted(C& c, const E& e) { 24 | const auto pos{ stdr::lower_bound(c,e) }; 25 | c.insert(pos, e); 26 | } 27 | 28 | int main() { 29 | std::vector v{ "2","1","3"}; 30 | psorted(v);//无序 31 | 32 | stdr::sort(v); 33 | psorted(v);//有序 34 | 35 | //v.emplace_back("0"); 36 | //psorted(v);//无序 37 | 38 | ::insert_sorted(v, "0"); 39 | psorted(v);//有序,相比于普通插入的优势 40 | //用list测试改写泛型的版本 41 | std::listlist{ 1,2,3,4,5 }; 42 | psorted(list);//有序 43 | ::insert_sorted(list, 0); 44 | psorted(list);//有序 45 | } -------------------------------------------------------------------------------- /src/3.7高效的将元素插入到map中.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | 3 | struct X { 4 | std::string s; 5 | X() { print("default construct\n"); } 6 | X(const char* s) :s{ s } { print("construct\n"); } 7 | X(const X&) { print("copy construct\n"); } 8 | }; 9 | void printm(const std::map& map) { 10 | for (const auto& [k, v] : map) { 11 | print("[ {}:{} ]", k, v.s); 12 | } 13 | print("\n"); 14 | } 15 | 16 | int main() { 17 | std::mapmap{}; 18 | map[1] = "🐴";//两个构造的开销,有参和默认 19 | print("\n"); 20 | //直接转发,只有一个有参构造的开销,这里使用try_emplace和emplace效果完全一样 21 | map.emplace(2,"🥵"); 22 | map.emplace(3, "🤣"); 23 | printm(map); 24 | print("\n"); 25 | 26 | map.emplace(1, "乐");//添加一个具有重复键的元素 27 | map.try_emplace(1, "乐"); 28 | printm(map); 29 | } 30 | //重复键元素的问题参见 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92300 -------------------------------------------------------------------------------- /src/3.8高效的修改map项的键值.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | template 5 | bool node_swap(M& m, K k1, K k2) { 6 | //extract 是更换 map 的键而不重分配的唯一方式 7 | auto node1{ m.extract(k1) }; 8 | auto node2{ m.extract(k2) }; 9 | if (node1.empty() || node2.empty()) 10 | return false; 11 | std::swap(node1.key(), node2.key()); 12 | m.insert(std::move(node1)); 13 | m.insert(std::move(node2)); 14 | return true; 15 | } 16 | 17 | int main() { 18 | std::mapmaps{ 19 | {1,"🐴"},{2,"🥵"},{3,"🤣"},{4,"🐭"},{5,"😘"} 20 | }; 21 | print(maps); 22 | ::node_swap(maps, 3, 5); 23 | print(maps); 24 | 25 | auto node = maps.extract(maps.begin()); 26 | node.key() = 5; 27 | auto t =maps.insert(std::move(node)); 28 | print(maps); 29 | if (!t.inserted) { 30 | print("插入失败 {}\n",t.position->second); 31 | } 32 | } -------------------------------------------------------------------------------- /src/3.9自定义键值的unordered_map.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | struct Coord { 6 | int x{}; 7 | int y{}; 8 | }; 9 | auto operator==(const Coord& a, const Coord& b) { 10 | return a.x == b.x && a.y == b.y; 11 | } 12 | namespace std { 13 | template<> 14 | struct hash { 15 | size_t operator()(const Coord&a)const { 16 | return static_cast(a.x) + static_cast(a.y); 17 | } 18 | }; 19 | } 20 | template 21 | inline void print(const std::unordered_map& map) { 22 | print("size: {} ", map.size()); 23 | for (auto& [k, v] : map)print("{{{} {}}}:{} ", k.x, k.y, v); 24 | print("\n"); 25 | } 26 | int main() { 27 | std::unordered_mapmap{ {{1,1},"😘"},{{0,0},"🤣"} }; 28 | print(map); 29 | } -------------------------------------------------------------------------------- /src/4.10创建随机访问迭代器.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | template 6 | class Container { 7 | 8 | class iterator { 9 | 10 | T* ptr_; 11 | public: 12 | using iterator_concept = std::contiguous_iterator_tag; 13 | using iterator_category = std::contiguous_iterator_tag; 14 | using value_type = std::remove_cv_t; 15 | using difference_type = std::ptrdiff_t; 16 | using pointer = const T*; 17 | using reference = const T&; 18 | 19 | iterator(T* ptr_ = nullptr) :ptr_{ ptr_ } {} 20 | 21 | const auto operator<=>(const iterator& o)const { 22 | ptr_ <=> o.ptr_; 23 | } 24 | 25 | iterator operator+(size_t size)const { 26 | return { ptr_ + size }; 27 | } 28 | 29 | friend const iterator operator+(size_t size, const iterator& o) { 30 | return { o.ptr_ + size }; 31 | } 32 | 33 | const iterator operator-(size_t size)const { 34 | return{ ptr_ - size }; 35 | } 36 | 37 | const size_t operator-(const iterator& o)const { 38 | return ptr_ - o.ptr_ ; 39 | } 40 | 41 | iterator& operator++() { 42 | ++ptr_; 43 | return *this; 44 | } 45 | 46 | iterator operator++(int) { 47 | auto tmp{ *this }; 48 | ++* this; 49 | return tmp; 50 | } 51 | 52 | iterator& operator--() { 53 | --ptr_; 54 | return *this; 55 | } 56 | 57 | iterator operator--(int) { 58 | auto tmp{ *this }; 59 | --* this; 60 | return tmp; 61 | } 62 | 63 | iterator& operator+=(size_t size)const { 64 | ptr_ += size; 65 | return *this; 66 | } 67 | 68 | iterator& operator-=(size_t size)const { 69 | ptr_ -= size; 70 | return *this; 71 | } 72 | 73 | const reference operator[](size_t size)const { 74 | return ptr_[size]; 75 | } 76 | 77 | const bool operator==(const iterator& o)const { 78 | return ptr_ == o.ptr_; 79 | } 80 | 81 | bool operator!=(const iterator& o)const { 82 | return ptr_ != o.ptr_; 83 | } 84 | 85 | reference operator*()const { 86 | return *ptr_; 87 | } 88 | 89 | T* operator->()const { 90 | return ptr_; 91 | } 92 | 93 | }; 94 | 95 | size_t n_elements_{}; 96 | std::unique_ptrc_{}; 97 | public: 98 | Container(std::initializer_listl) :n_elements_{ l.size() }, c_{ std::make_unique(n_elements_) } 99 | { 100 | for (size_t index{}; auto e : l) { 101 | c_[index++] = e; 102 | } 103 | } 104 | 105 | Container(size_t sz) :n_elements_{ sz }, c_{ std::make_unique(n_elements_) } {} 106 | 107 | size_t size()const { 108 | return n_elements_; 109 | } 110 | 111 | const T& operator[](size_t index)const { 112 | return c_[index]; 113 | } 114 | 115 | const T& at(size_t index)const { 116 | return index < n_elements_ ? c_[index] : throw std::out_of_range{ "Container::at(): index out of range" }; 117 | } 118 | 119 | bool empty() const { 120 | return (n_elements_ == 0); 121 | } 122 | 123 | iterator begin()const { return { c_.get() }; } 124 | iterator end()const { return { c_.get() + n_elements_ }; } 125 | }; 126 | 127 | template 128 | Container(std::initializer_listl) -> Container; 129 | 130 | struct X { 131 | int x; 132 | }; 133 | 134 | int main() { 135 | Container v{1,2,3,4,5}; 136 | for (const auto& i : v) { 137 | print("{} ", i); 138 | } 139 | print("\n"); 140 | 141 | Containerv3{ {1},{2} }; 142 | auto ret2 = v3.begin(); 143 | ret2->x; 144 | print("{}\n", std::ranges::forward_range>); 145 | print("{}\n", std::ranges::range>); 146 | print("{}\n", std::ranges::viewable_range>); 147 | print("{}\n", std::bidirectional_iterator>); 148 | 149 | for (const auto& i : v | std::views::reverse) { 150 | print("{} ", i); 151 | } 152 | 153 | } -------------------------------------------------------------------------------- /src/4.3创建可迭代范围.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | 3 | template 4 | class Seq { 5 | T _star{}; 6 | T _end{}; 7 | public: 8 | Seq(T star, T end) :_star(star), _end(end) {} 9 | struct iterator { 10 | T value{}; 11 | explicit iterator(T v) :value(v) {} 12 | iterator& operator++() { 13 | value++; 14 | return *this; 15 | } 16 | T operator*() { 17 | return value; 18 | } 19 | bool operator!=(const iterator& l) { 20 | return this->value != l.value; 21 | } 22 | }; 23 | iterator begin() { 24 | return iterator{ _star }; 25 | } 26 | iterator end() { 27 | return iterator{ _end }; 28 | } 29 | }; 30 | 31 | template 32 | struct X { 33 | T array[size]{}; 34 | T* begin() { 35 | return array; 36 | } 37 | T* end() { 38 | return array + size; 39 | } 40 | }; 41 | 42 | int main() { 43 | Seqv{ 1,10 }; 44 | for (auto i : v) { 45 | print("{} ", i); 46 | } 47 | print("\n"); 48 | 49 | Xx{ 1,2,3,4,5,6,7,8,9,10 }; 50 | for (auto i : x) { 51 | print("{} ", i); 52 | } 53 | } -------------------------------------------------------------------------------- /src/4.4使迭代器与STL迭代器特性兼容.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | 3 | template 4 | class Seq { 5 | T _star{}; 6 | T _end{}; 7 | public: 8 | Seq(T star, T end) :_star(star), _end(end) {} 9 | struct iterator { 10 | T value{}; 11 | 12 | using value_type = std::remove_cv_t; 13 | using difference_type = std::ptrdiff_t; 14 | using pointer = const T*; 15 | using reference = const T&; 16 | 17 | explicit iterator(T v=0) :value(v) {} 18 | iterator& operator++() { 19 | value++; 20 | return *this; 21 | } 22 | iterator operator++(int) { 23 | auto t{ *this }; 24 | ++ *this; 25 | return t; 26 | } 27 | T operator*()const { 28 | return value; 29 | } 30 | bool operator!=(const iterator& l)const noexcept{ 31 | return this->value != l.value; 32 | } 33 | bool operator==(const iterator& l)const noexcept { 34 | return this->value == l.value; 35 | } 36 | }; 37 | iterator begin()const { 38 | return iterator{ _star }; 39 | } 40 | iterator end()const { 41 | return iterator{ _end }; 42 | } 43 | }; 44 | 45 | template 46 | requires std::forward_iterator 47 | void printc(const T& r) { 48 | for (const auto& i : r) { 49 | print("{} ", i); 50 | } 51 | print("\n"); 52 | } 53 | 54 | int main() { 55 | Seqr{ 100,110 }; 56 | //auto [min_it, max_it] = std::minmax_element(r.begin(), r.end()); 57 | auto [min_it, max_it] = std::ranges::minmax_element(r); 58 | print("max:{} min:{}\n", max_it.value, min_it.value); 59 | printc(r); 60 | static_assert(std::ranges::forward_range>); 61 | } -------------------------------------------------------------------------------- /src/4.5使用迭代器适配器填充STL容器.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | std::dequed1{ 1,2,3,4,5 }; 10 | std::dequed2(d1.size()); 11 | std::copy(d1.begin(), d1.end(), d2.begin()); 12 | printc(d2, "d2 after copy"); 13 | 14 | std::copy(d1.begin(), d1.end(), std::back_inserter(d2)); 15 | printc(d2, "d2 after back_inserter"); 16 | 17 | std::dequed3{ 47,73,114,138,54 }; 18 | std::copy(d3.begin(), d3.end(), std::front_inserter(d2)); 19 | printc(d2, "d2 after front_inserter"); 20 | 21 | auto it2{ d2.begin() + 2 }; 22 | std::copy(d1.begin(), d1.end(), std::inserter(d2, it2)); 23 | printc(d2, "d2 after minddle insert"); 24 | 25 | print("ostream_iterator:"); 26 | std::copy(d1.begin(), d1.end(), std::ostream_iterator{std::cout," "}); 27 | print("\n"); 28 | 29 | /*std::vectorvs{}; 30 | std::copy(std::istream_iterator(std::cin), {}, std::back_inserter(vs)); 31 | printc(vs, "vs2");*/ 32 | 33 | /*std::vector V(std::istream_iterator(std::cin), {}); 34 | printc(V, "V");*/ 35 | 36 | for (auto it = std::istream_iterator(std::cin); 37 | it != std::istream_iterator{}; ++it) { 38 | print("{} ", *it); 39 | } 40 | } -------------------------------------------------------------------------------- /src/4.6创建一个迭代器生成器.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | 3 | class fib_generator { 4 | using fib_t = unsigned long; 5 | fib_t stop_{}; 6 | fib_t count_{ 0 }; 7 | fib_t a_{ 0 }; 8 | fib_t b_{ 1 }; 9 | constexpr void do_fib() { 10 | const fib_t old_d = b_; 11 | b_ += a_; 12 | a_ = old_d; 13 | } 14 | public: 15 | using iterator_concept = std::forward_iterator_tag; 16 | using iterator_category = std::forward_iterator_tag; 17 | using value_type = std::remove_cv_t; 18 | using difference_type = std::ptrdiff_t; 19 | using pointer = const fib_t*; 20 | using reference = const fib_t&; 21 | 22 | explicit fib_generator(fib_t stop = 0) :stop_{ stop } {} 23 | 24 | fib_t operator*()const { return b_; } 25 | constexpr fib_generator& operator++() { 26 | do_fib(); 27 | ++count_; 28 | return *this; 29 | } 30 | fib_generator operator++(int) { 31 | auto tmp{ *this }; 32 | ++* this; 33 | return tmp; 34 | } 35 | bool operator==(const fib_generator& o)const { 36 | return count_ == o.count_; 37 | } 38 | const fib_generator& begin()const { return *this; } 39 | const fib_generator end()const { 40 | auto sentinel = fib_generator(); 41 | sentinel.count_ = stop_; 42 | return sentinel; 43 | } 44 | fib_t size() { return stop_; } 45 | }; 46 | 47 | int main() { 48 | printc(fib_generator(10)); 49 | fib_generator fib(10); 50 | auto x = std::ranges::views::transform(fib, [](auto x) {return x * x; }); 51 | printc(x, "squared:"); 52 | } -------------------------------------------------------------------------------- /src/4.7反向迭代器的反向适配器.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | int main() { 6 | int array[]{ 1,2,3,4,5 }; 7 | printc(array, "c-array"); 8 | auto it = std::begin(array); 9 | auto it_end = std::end(array); 10 | while (it != it_end) { 11 | print("{} ", *it++); 12 | } 13 | print("\n"); 14 | 15 | auto it2 = std::rbegin(array); 16 | auto it_end2 = std::rend(array); 17 | while (it2 != it_end2) { 18 | print("{} ", *it2++); 19 | } 20 | print("\n"); 21 | 22 | printr(array, "rev c-array"); 23 | 24 | std::vectorv{ 1,2,3,4,5 }; 25 | printc(v, "vector"); 26 | printr(v, "rev vector"); 27 | } -------------------------------------------------------------------------------- /src/4.8用哨兵迭代未知长度的对象.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | class cstr_it { 5 | const char* s{}; 6 | static constexpr const char nullchar = '\0'; 7 | public: 8 | explicit cstr_it(const char* str) :s{ str } {} 9 | char operator*()const { return *s; } 10 | cstr_it& operator++() { 11 | ++s; 12 | return *this; 13 | } 14 | bool operator!=(const char)const { 15 | return s != nullptr && *s != nullchar; 16 | } 17 | cstr_it begin()const { return *this; } 18 | const char end()const { return nullchar; } 19 | }; 20 | 21 | void print_cstr(const char* s) { 22 | print("{}: ", s); 23 | for (char c : cstr_it(s)) { 24 | print("{:02x} ", c); 25 | } 26 | print("\n"); 27 | } 28 | 29 | int main() { 30 | const char carray[]{ "array" }; 31 | print_cstr(carray); 32 | const char* cstr{ "c-string" }; 33 | print_cstr(cstr); 34 | } -------------------------------------------------------------------------------- /src/4.9构建zip迭代器适配器.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | template 6 | class zip_iterator { 7 | using val_t = typename T::value_type; 8 | using ret_t = std::pair; 9 | using it_t = typename T::iterator; 10 | 11 | it_t ita_{}; 12 | it_t itb_{}; 13 | it_t ita_begin_{}; 14 | it_t itb_begin_{}; 15 | it_t ita_end_{}; 16 | it_t itb_end_{}; 17 | zip_iterator(it_t ita, it_t itb) :ita_{ ita }, itb_{ itb } {}//用作begin和end返回的迭代器构造函数 18 | 19 | public: 20 | using value_type = std::pair; 21 | using difference_type = long int; 22 | using pointer = const val_t*; 23 | using reference = const val_t&; 24 | 25 | zip_iterator(T& a, T& b) : 26 | ita_{ a.begin() }, itb_{ b.begin() }, ita_begin_{ ita_ }, itb_begin_{ itb_ }, ita_end_{ a.end() }, itb_end_{ b.end() } {} 27 | zip_iterator& operator++() { 28 | ++ita_; 29 | ++itb_; 30 | return *this; 31 | } 32 | bool operator==(const zip_iterator& o)const { return ita_ == o.ita_ || itb_ == o.itb_; } 33 | bool operator!=(const zip_iterator& o)const { return !operator==(o); } 34 | ret_t operator*()const {return { *ita_,*itb_ };} 35 | zip_iterator begin()const { return { ita_begin_,itb_begin_ }; } 36 | zip_iterator end()const { return { ita_end_,itb_end_ }; } 37 | }; 38 | 39 | int main() { 40 | std::vectorvec_a{ "Bob","John","Joni","🤣" }; 41 | std::vectorvec_b{ "Dylan","Williams","Mitchell" }; 42 | 43 | printc(vec_a, "vec_a: "); 44 | printc(vec_b, "vec_b: "); 45 | 46 | print("zipped: "); 47 | for (const auto& [a, b] : zip_iterator{ vec_a, vec_b }) { 48 | print("[{}, {}] ", a, b); 49 | } 50 | print("\n"); 51 | 52 | std::mapname_map{}; 53 | for (auto [a, b] : zip_iterator{ vec_a,vec_b }) {//插入到map中 54 | name_map.emplace(a, b); 55 | } 56 | print(name_map);//打印 57 | 58 | } -------------------------------------------------------------------------------- /src/5.3用于作用域可重用代码.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | 3 | int main() { 4 | auto one = []() {return "one"; }; 5 | auto two = [] {return "two"; }; 6 | print("{} {}\n", one(), two()); 7 | 8 | auto p = [](auto f) {//泛型lambda,C++20之前只能使用这种方式 9 | print("{}\n", f()); 10 | }; 11 | p([] {return "乐"; }); 12 | 13 | auto p2 = [](T&& f) { print("{}\n", f()); }; 14 | p2(one); 15 | p2(std::move(one)); 16 | 17 | [] (T&& f) { print("{}\n", f()); }(two); 18 | 19 | int num{}; 20 | auto p3 = [num]()mutable {num++; }; 21 | for (auto i = 0; i < 5; i++)p3(); 22 | 23 | print("{}\n", num); 24 | 25 | auto p4 = [&]()mutable {num++; }; 26 | print("{}\n", sizeof(p4)); 27 | 28 | constexpr int n = []()constexpr {return 10 * 10; }(); 29 | 30 | auto p5 = []()->int {return 10; }; 31 | } -------------------------------------------------------------------------------- /src/5.4算法库中作为谓词.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | bool is_div4(int i) { 5 | return i % 4 == 0; 6 | } 7 | 8 | struct is_div4_ { 9 | bool operator()(int i) { 10 | return i % 4 == 0; 11 | } 12 | }; 13 | 14 | auto is_div_by(int divisor) { 15 | return [=](int i) {return i % divisor == 0; }; 16 | } 17 | 18 | int main() { 19 | std::vector v{ 1,2,3,4,44,8,10 }; 20 | auto count1 =std::count_if(v.begin(), v.end(), is_div4); 21 | auto count2 = std::count_if(v.begin(), v.end(), is_div4_{}); 22 | print("{} {}\n", count1, count2); 23 | auto count3 = std::count_if(v.begin(), v.end(), [](int i) {return i % 4 == 0; }); 24 | print("{}\n", count3); 25 | 26 | for (int i : {3, 4, 5}) { 27 | auto count = std::ranges::count_if(v, is_div_by(i)); 28 | print("{} ", count); 29 | } 30 | 31 | //不带捕获的lambda表达式可以有转换函数,隐式转换到对应的函数指针 32 | int(*p)(int) = [](int a) {return a; }; 33 | print("{}\n", p(10)); 34 | } -------------------------------------------------------------------------------- /src/5.5与function一起作为多态包装器.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void hello() { 8 | print("hello\n"); 9 | } 10 | 11 | struct Hello_ { 12 | void greeting() { 13 | print("hello\n"); 14 | } 15 | }; 16 | 17 | int main() { 18 | std::dequed; 19 | std::listl; 20 | std::vectorv; 21 | 22 | auto print_c = [](const auto& c) { 23 | for (const auto& i : c)print("{} ", i); 24 | print("\n"); 25 | }; 26 | auto push_c = [](auto& container) { 27 | return [&container](auto value) { 28 | container.push_back(value); 29 | }; 30 | }; 31 | const std::vector>consumers{ push_c(d),push_c(l),push_c(v) }; 32 | //consumers[0](10); 33 | //print_c(d); 34 | for (auto& i : consumers) { 35 | for (size_t j = 0; j < 10; j++) { 36 | i(j); 37 | } 38 | } 39 | print_c(d); 40 | print_c(l); 41 | print_c(v); 42 | 43 | std::function f{ hello }; 44 | f(); 45 | Hello_ h; 46 | std::functionff{ std::bind(&Hello_::greeting,&h) }; 47 | ff(); 48 | std::bind(&Hello_::greeting, &h)(); 49 | } -------------------------------------------------------------------------------- /src/5.6用递归连接lambda.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | template 3 | auto concat(F t, Ts ...ts){ 4 | if constexpr (sizeof...(ts) > 0) { 5 | return [=](auto ...parameters) { 6 | return t(concat(ts...)(parameters...)); 7 | }; 8 | } 9 | else { 10 | return t; 11 | } 12 | } 13 | int main() { 14 | auto twice = [](auto i) {return i * 2; }; 15 | auto thrice = [](auto i) {return i * 3; }; 16 | auto combined = concat(thrice, twice, std::plus{}); 17 | print("{} \n", combined(2, 3)); 18 | } -------------------------------------------------------------------------------- /src/5.7将谓词与逻辑连接词连接起来.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | static bool begins_with_a(const std::string& s) 5 | { 6 | return s.find("a") == 0; 7 | } 8 | static bool ends_with_b(const std::string& s) 9 | { 10 | return s.rfind("b") == s.length() - 1; 11 | } 12 | 13 | template 14 | auto combine(F binary_func, A a, B b) { 15 | return [=](auto param) { 16 | return binary_func(a(param), b(param)); 17 | }; 18 | } 19 | 20 | int main() { 21 | auto a_xxx_b{ combine(std::logical_and{},begins_with_a, ends_with_b) }; 22 | 23 | std::copy_if(std::istream_iterator{std::cin}, {}, 24 | std::ostream_iterator{std::cout, ", "}, a_xxx_b); 25 | std::cout << '\n'; 26 | } -------------------------------------------------------------------------------- /src/5.8用相同的输入调用多个lambda.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | 3 | auto braces(const char a, const char b) { 4 | return [a, b](const auto v) { 5 | print("{}{}{} ", a, v, b); 6 | }; 7 | } 8 | 9 | int main() { 10 | auto a = braces('(', ')'); 11 | auto b = braces('[', ']'); 12 | auto c = braces('{', '}'); 13 | auto d = braces('|', '|'); 14 | for (int i : {1, 2, 3, 4, 5}) { 15 | for (auto x : { a,b,c,d }) { 16 | x(i); 17 | } 18 | print("\n"); 19 | } 20 | } -------------------------------------------------------------------------------- /src/5.9对跳转表使用映射lambda.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | 3 | const char prompt(const char* p) { 4 | std::string r; 5 | print("{} > ", p); 6 | std::getline(std::cin, r, '\n'); 7 | 8 | if (r.size() < 1) return '\0';//如果走这个分支,就是直接下一个循环 9 | if (r.size() > 1) { 10 | print("响应时间过长\n"); 11 | return '\0'; 12 | } 13 | return toupper(r[0]); 14 | } 15 | 16 | int main() { 17 | using jumpfunc = void(*)(); 18 | 19 | std::map jumpmap{ 20 | { 'A', [] { print("func A\n"); } }, 21 | { 'B', [] { print("func B\n"); } }, 22 | { 'C', [] { print("func C\n"); } }, 23 | { 'D', [] { print("func D\n"); } }, 24 | { 'X', [] { print("Bye!\n"); } } 25 | }; 26 | 27 | char select{}; 28 | while (select != 'X') { 29 | if ((select = prompt("select A/B/C/D/X"))) { 30 | auto it = jumpmap.find(select); 31 | if (it != jumpmap.end()) it->second(); 32 | else print("没有对应的选项!\n"); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/6.10合并已排序容器.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vectorvs1{ "dog","cat","veloiraptor" }; 7 | std::vectorvs2{ "kirk","sulu","spock" }; 8 | std::vectordest{}; 9 | printc(vs1, "vs1"); 10 | printc(vs2, "vs2"); 11 | 12 | std::ranges::sort(vs1); 13 | std::ranges::sort(vs2); 14 | printc(vs1, "vs1"); 15 | printc(vs2, "vs2"); 16 | 17 | std::merge(vs1.begin(), vs1.end(), vs2.begin(), vs2.end(), std::back_inserter(dest)); 18 | printc(dest, "dest"); 19 | } -------------------------------------------------------------------------------- /src/6.2基于迭代器的复制.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | namespace stdr = std::ranges; 4 | 5 | int main() { 6 | std::vectorv1{ "alpha","beta","gamma","delta","epsilon" }; 7 | printc(v1,"v1"); 8 | std::vectorv2(v1.size()); 9 | std::copy(v1.begin(), v1.end(), v2.begin()); 10 | printc(v2, "v2"); 11 | 12 | std::copy(v1.begin(), v1.end(), std::back_inserter(v2)); 13 | printc(v2, "v2"); 14 | 15 | std::vectorv3{}; 16 | std::copy_n(v1.begin(), 3, std::back_inserter(v3)); 17 | printc(v3, "v3"); 18 | 19 | std::vectorv4{}; 20 | /*std::copy_if(v1.begin(), v1.end(), std::back_inserter(v4), [](auto& s) { 21 | return s.size() > 4; 22 | });*/ 23 | stdr::copy_if(v1,std::back_inserter(v4), [](auto& s) { 24 | return s.size() > 4; 25 | }); 26 | printc(v4, "v4"); 27 | 28 | stdr::copy(v1, std::ostream_iterator{std::cout, " "}); 29 | print("\n"); 30 | 31 | stdr::move(v1, v2.begin()); 32 | printc(v1, "after move: v1"); 33 | printc(v2, "after move: v2"); 34 | } -------------------------------------------------------------------------------- /src/6.3将容器元素连接到以供字符串当中.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace bw { 8 | template 9 | std::ostream& join(T it, T end_it, std::ostream& o, std::string_view sep = "") { 10 | if (it != end_it)o << *it++; 11 | while (it != end_it)o << sep << *it++; 12 | return o; 13 | } 14 | 15 | template 16 | std::string join(I it, I end_it, std::string_view sep = "") { 17 | std::ostringstream ostr; 18 | join(it, end_it, ostr, sep); 19 | return ostr.str(); 20 | } 21 | 22 | std::string join(const auto& c, std::string_view sep = "") { 23 | return join(std::begin(c), std::end(c), sep); 24 | } 25 | } 26 | 27 | int main() { 28 | std::vectorgreek{ "alpha","beta","gamma", 29 | "delta","epsilon" }; 30 | for (const auto& c : greek) std::cout << c << ","; 31 | print("\n"); 32 | auto greek_view = greek | std::views::join; 33 | for (const auto& c : greek_view) std::cout << c; 34 | print("\n"); 35 | 36 | bw::join(greek.begin(), greek.end(), std::cout, ", ") << '\n'; 37 | 38 | auto s = bw::join(greek.begin(), greek.end(), ", "); 39 | print("{}\n", s); 40 | 41 | auto s2 = bw::join(greek, ", "); 42 | print("{}\n", s2); 43 | 44 | std::listlist{ std::numbers::pi,std::numbers::e,std::numbers::sqrt2 }; 45 | print("{}\n", bw::join(list, ": ")); 46 | } -------------------------------------------------------------------------------- /src/6.4sort排序容器元素.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | void check_sorted(auto& c) { 6 | if (!std::is_sorted(c.begin(), c.end()))print("un"); 7 | print("sorted: "); 8 | } 9 | 10 | void printc_(const auto& c) { 11 | check_sorted(c); 12 | for (auto& e : c)print("{} ", e); 13 | print("\n"); 14 | } 15 | 16 | void randomize(auto& c) { 17 | static std::random_device rd; 18 | static std::default_random_engine rng(rd()); 19 | std::shuffle(c.begin(), c.end(), rng); 20 | } 21 | 22 | struct things { 23 | std::string s_; 24 | int i_; 25 | std::string str()const { 26 | return std::format("({}, {})", s_, i_); 27 | } 28 | }; 29 | 30 | void print_things(const auto& c) { 31 | for (auto& v : c)print("{} ", v.str()); 32 | print("\n"); 33 | } 34 | 35 | int main() { 36 | std::vectorv{ 1,2,3,4,5,6,7,8,9,10 }; 37 | printc_(v); 38 | 39 | for (int i{ 3 }; i; i--) { 40 | randomize(v); 41 | printc_(v); 42 | } 43 | std::sort(v.begin(), v.end()); 44 | printc_(v); 45 | 46 | print("partial_sort:\n"); 47 | randomize(v); 48 | auto middle{ v.begin() + (v.size() / 2) }; 49 | std::partial_sort(v.begin(), middle, v.end()); 50 | printc_(v); 51 | 52 | std::partition(v.begin(), v.end(), [](int i) {return i > 5; }); 53 | printc_(v); 54 | 55 | std::vectorvthings{ {"🐴",1},{"😘",2},{"🤣",3},{"🥵",4},{"🤡",5} }; 56 | std::sort(vthings.begin(), vthings.end(), 57 | [](const things& lhs, const things& rhs) { 58 | return lhs.i_ > rhs.i_; 59 | }); 60 | 61 | print_things(vthings); 62 | } -------------------------------------------------------------------------------- /src/6.5transform修改容器内容.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | std::string str_lower(const std::string& s) { 5 | std::string outstr{}; 6 | for (const char& c : s) { 7 | outstr += tolower(c); 8 | } 9 | return outstr; 10 | } 11 | 12 | int main() { 13 | std::vectorv1{ 1,2,3,4,5,6,7,8,9,10 }; 14 | std::vectorv2; 15 | printc(v1, "v1"); 16 | std::transform(v1.begin(), v1.end(), std::back_inserter(v2), [](int x) {return x * x; }); 17 | printc(v2, "v2"); 18 | 19 | std::vectorvstr1{ "Aaa","Bbb","Ccc","DDD" }; 20 | std::vectorvstr2; 21 | printc(vstr1, "vstr1"); 22 | print("str_lower:\n"); 23 | std::transform(vstr1.begin(), vstr1.end(), std::back_inserter(vstr2), 24 | [](std::string& x) {return str_lower(x); }); 25 | printc(vstr2, "vstr2"); 26 | 27 | print("ranges sequares:\n"); 28 | auto view1 = std::views::transform(v1, [](int x) {return x * x; }); 29 | printc(view1, "view1"); 30 | 31 | v2.clear(); 32 | std::ranges::transform(v1, std::back_inserter(v2), [](int x) {return x * x; }); 33 | printc(v2, "v2"); 34 | } -------------------------------------------------------------------------------- /src/6.6查找特定项.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | struct City { 6 | std::string name{}; 7 | unsigned pop{}; 8 | bool operator==(const City& o)const { 9 | return name == o.name; 10 | } 11 | std::string str()const { 12 | return std::format("[{}, {}]", name, pop); 13 | } 14 | }; 15 | 16 | int main() { 17 | const std::vectorv{ 1,2,3,4,5,6,7,8,9,10 }; 18 | 19 | auto it1 = std::find(v.begin(), v.end(), 7); 20 | if (it1 != v.end())print("found: {}\n", *it1); 21 | else print("not found:\n"); 22 | 23 | const std::vectorc{ 24 | {"London",8425622}, 25 | {"Berlin",3566791}, 26 | {"Tokyo",37435191}, 27 | {"Cairo",20485965} 28 | }; 29 | auto it2 = std::find(c.begin(), c.end(), City{ "Berlin" }); 30 | if (it2 != c.end())print("found: {}\n", it2->str()); 31 | else print("not found:\n"); 32 | 33 | auto it3 = std::find_if(begin(c), end(c), [](const City& item) { 34 | return item.pop > 20000000; 35 | }); 36 | if (it3 != c.end())print("found: {}\n", it3->str()); 37 | else print("not found:\n"); 38 | 39 | auto vwl = std::views::filter(c, [](const City& item) { 40 | return item.pop > 20000000; 41 | }); 42 | for (const City& e : vwl)print("{}\n", e.str()); 43 | } -------------------------------------------------------------------------------- /src/6.7将容器元素限制在clamp范围内.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | constexpr int ilow{ 0 }; 6 | constexpr int ihigh{ 500 }; 7 | 8 | void printc_(const std::ranges::range auto& v, std::string_view s = "") { 9 | for (const auto& i : v)print("{:>5} ", i); 10 | print("\n"); 11 | } 12 | 13 | int main() { 14 | auto il = { 0,-12,2001,4,5,-14,100,200 }; 15 | std::vectorvoi{ il }; 16 | print("vector voi before:\n"); 17 | printc_(voi); 18 | 19 | print("vector voi after:\n"); 20 | for (auto& e : voi)e = std::clamp(e, ilow, ihigh); 21 | printc_(voi); 22 | 23 | print("list loi before:\n"); 24 | std::listloi{ il }; 25 | printc_(loi); 26 | std::transform(loi.begin(), loi.end(), loi.begin(), [](auto e) { 27 | return std::clamp(e, ilow, ihigh); 28 | }); 29 | print("list loi after:\n"); 30 | printc_(loi); 31 | } -------------------------------------------------------------------------------- /src/6.8sample采集样本数据集.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | 6 | int iround(const double& d) { 7 | return static_cast(std::round(d));//四舍五入返回double,进行显式类型转换 8 | } 9 | 10 | int main() { 11 | constexpr size_t n_data{ 200000 };//数据大小 12 | constexpr size_t n_samples{ 500 };//样本容器大小 13 | constexpr int mean{ 0 };//均值 14 | constexpr size_t dev{ 3 };//方差 15 | 16 | std::random_device rd;//提供对硬件随机数生成器的访问 17 | std::mt19937 rng{ rd() };//随机数生成器 18 | std::normal_distribution<>dist{ mean,dev };//正态分布的两个参数 均值与方差 19 | std::arraydata{}; 20 | for (auto& e : data)e = iround(dist(rng)); 21 | 22 | std::arraysamples{}; 23 | std::sample(data.begin(), data.end(), samples.begin(), n_samples, rng); 24 | 25 | std::map hist{}; 26 | for (const int i : samples) ++hist[i]; 27 | 28 | constexpr size_t scale{ 3 }; 29 | print("{:>3} {:>5} {:<}/{}\n", "n", "count", "graph", "scale"); 30 | for (const auto& [value, count] : hist) { 31 | print("{:>3} ({:>3}) {}\n", value, count, std::string(count , '*')); 32 | } 33 | } -------------------------------------------------------------------------------- /src/6.9生成有序数据序列.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vectorvs{ "dog","cat","velociraptor" }; 7 | std::sort(vs.begin(), vs.end()); 8 | do { 9 | printc(vs); 10 | } while (std::next_permutation(vs.begin(), vs.end())); 11 | 12 | std::vectorv{ 1,2,3 }; 13 | do 14 | { 15 | printc(v); 16 | } while (std::next_permutation(v.begin(),v.end())); 17 | print("从大到小:\n"); 18 | std::sort(v.begin(), v.end(), std::greater{}); 19 | do 20 | { 21 | printc(v); 22 | } while (std::next_permutation(v.begin(), v.end())); 23 | } -------------------------------------------------------------------------------- /src/7.10使用文件输入初始化复杂结构体.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | struct City { 5 | std::string name; 6 | unsigned long population; 7 | double latitude; 8 | double longitude; 9 | }; 10 | 11 | std::istream& operator>>(std::istream& in, City& c) { 12 | in >> std::ws; 13 | std::getline(in, c.name); 14 | in >> c.population >> c.latitude >> c.longitude; 15 | return in; 16 | } 17 | std::string make_commas(const unsigned long num) {//把数字串中间添加逗号,三位一个逗号分隔 18 | std::string s{ std::to_string(num) }; 19 | for (int l = s.length() - 3; l > 0; l -= 3) 20 | s.insert(l, ","); 21 | return s; 22 | } 23 | 24 | int main() { 25 | constexpr const char* fn{ "E:/自制视频教程/《C++20 STL Cookbook》2023/src/src/cities.txt" }; 26 | std::vectorcities; 27 | std::ifstream infile(fn, std::ios_base::in); 28 | if (!infile.is_open()) { 29 | print("failed to open file {}\n", fn); 30 | return 1; 31 | } 32 | for (City c{}; infile >> c;)cities.emplace_back(c); 33 | 34 | for (const auto& [name, pop, lat, lon] : cities) { 35 | print("{:.<15} pop {:<15} coords {}, {}\n", name, make_commas(pop), lat, lon); 36 | } 37 | } -------------------------------------------------------------------------------- /src/7.11使用char_traits.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | 3 | constexpr char char_lower(const char& c) {//全部转换为小写 4 | if (c >= 'A' && c <= 'Z')return c + 32; 5 | else return c; 6 | } 7 | 8 | class ci_traits :public std::char_traits { 9 | public: 10 | static constexpr bool lt(char_type a, char_type b)noexcept { 11 | return char_lower(a) < char_lower(b); 12 | } 13 | static constexpr bool eq(char_type a, char_type b)noexcept { 14 | return char_lower(a) == char_lower(b); 15 | } 16 | static constexpr int compare(const char_type* s1, const char_type* s2, size_t count) { 17 | for (size_t i{ 0 }; i < count; ++i) { 18 | auto diff{ char_lower(s1[i]) <=> char_lower(s2[i]) }; 19 | if (diff > 0)return 1; 20 | if (diff < 0)return -1; 21 | } 22 | return 0; 23 | } 24 | static constexpr const char_type* find(const char_type* p, size_t count, const char_type& ch) { 25 | const char_type find_c{ char_lower(ch) }; 26 | for (size_t i{ 0 }; i < count; ++i) { 27 | if (find_c == char_lower(p[i]))return p + i; 28 | } 29 | return nullptr; 30 | } 31 | }; 32 | 33 | using ci_string = std::basic_string; 34 | 35 | std::ostream& operator<<(std::ostream& os, const ci_string& str) { 36 | return os << str.c_str(); 37 | } 38 | 39 | class lc_traits : public std::char_traits { 40 | public: 41 | static constexpr void assign(char_type& r, const char_type& a)noexcept { 42 | r = char_lower(a); 43 | } 44 | static constexpr char_type* assign(char_type* p, std::size_t count, char_type a) { 45 | for (size_t i{ 0 }; i < count; ++i)p[i] = char_lower(a); 46 | return p; 47 | } 48 | static constexpr char_type* copy(char_type* dest, const char_type* src, size_t count) { 49 | for (size_t i{ 0 }; i < count; ++i) { 50 | dest[i] = char_lower(src[i]); 51 | } 52 | return dest; 53 | } 54 | }; 55 | using lc_string = std::basic_string; 56 | 57 | int main() { 58 | std::string s{ "🤣🤣" }; 59 | ci_string ci_s{ "🐴🐴B" }; 60 | std::cout << s << '\n' << ci_s << '\n'; 61 | 62 | ci_string compare1{"CompArE StRiNg"}; 63 | ci_string compare2{ "compare string" }; 64 | if (compare1 == compare2) { 65 | printf("Match! %s == %s\n", compare1.data(), compare2.data());//这里本来是要用format的,还是那句话,预览版的bug没消除 66 | }else { 67 | printf("no match %s != %s\n", compare1.data(), compare2.data()); 68 | } 69 | 70 | size_t found = ci_s.find('b'); 71 | std::cout << std::format("found: pos {} char {}\n", found, ci_s[found]); 72 | 73 | lc_string lc_s{ "Foo Bar Baz" }; 74 | std::cout << "lc_string: " << lc_s.c_str() << '\n';//直到2022年3月8日,预览版的bug,依旧没有消除 75 | } -------------------------------------------------------------------------------- /src/7.12用正则表达式解析字符串.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | template 6 | void get_links(It it) { 7 | for (It end_it{}; it != end_it;) { 8 | const std::string link{ *it++ }; 9 | if (it == end_it)break; 10 | const std::string desc{ *it++ }; 11 | print("{:.<24} {}\n", link, desc); 12 | } 13 | } 14 | 15 | int main() { 16 | const char* fn{ R"(E:\自制视频教程\《C++20 STL Cookbook》2023\src\src\the-end.html)" }; 17 | const std::regex link_re{ "([^<]*)" }; 18 | std::string in{}; 19 | std::ifstream infile{ fn,std::ios_base::in }; 20 | for (std::string line{}; std::getline(infile, line);)in += line; 21 | 22 | std::sregex_token_iterator it{ in.begin(),in.end(),link_re,{1,2} }; 23 | get_links(it); 24 | } -------------------------------------------------------------------------------- /src/7.3轻量字符串对象string_view.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | using namespace std::literals; 5 | 6 | std::string_view sv() { 7 | const char text[]{ "hello" }; 8 | std::string_view greeting{ text }; 9 | return greeting; 10 | } 11 | 12 | void f(const std::string& str) { 13 | 14 | } 15 | void f2(std::string_view str) { 16 | 17 | } 18 | 19 | int main() { 20 | char str[10]{ "hello" }; 21 | std::string str2{ str }; 22 | print("{}\n", str2); 23 | str[0] = 'a'; 24 | print("{}\n", str2); 25 | 26 | std::string_view sview{ str }; 27 | print("{}\n", sview); 28 | str[0] = 'b'; 29 | print("{}\n", sview); 30 | 31 | auto t = sv(); 32 | print("{}\n", t); 33 | 34 | print("{}\n", "hello"sv.substr(1,4)); 35 | 36 | constexpr std::string_view str3{ "哈哈" }; 37 | //constexpr std::string str4{ "哈哈" };//error 38 | 39 | print("{}\n", str3); 40 | 41 | std::string str4{ "1" }; 42 | const std::string str5{ "1" }; 43 | f(str4); 44 | f(str5); 45 | f("1");//开销大,需要构造临时的std::string对象 46 | 47 | f2("1"); 48 | f2(str4); 49 | f2(str5); 50 | } -------------------------------------------------------------------------------- /src/7.4连接字符串.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | using std::chrono::high_resolution_clock; 6 | using std::chrono::duration; 7 | 8 | void timer(auto(f)()->std::string) { 9 | auto t1 = high_resolution_clock::now(); 10 | std::string s{ f() }; 11 | auto t2 = high_resolution_clock::now(); 12 | durationms = t2 - t1; 13 | print("{}", s); 14 | print("duration: {} ms\n", ms.count()); 15 | } 16 | 17 | std::string concat_string() { 18 | print("concat_string\n"); 19 | std::string a{ "a" }; 20 | std::string b{ "b" }; 21 | long n{}; 22 | while (++n) { 23 | std::string x{}; 24 | x += a + ", " + b + "\n"; 25 | if (n >= 10000000)return x; 26 | } 27 | return "error\n"; 28 | } 29 | 30 | std::string append_string() { 31 | print("append_string\n"); 32 | std::string a{ "a" }; 33 | std::string b{ "b" }; 34 | long n{}; 35 | while (++n) { 36 | std::string x{}; 37 | x.append(a); 38 | x.append(", "); 39 | x.append(b); 40 | x.append("\n"); 41 | if (n >= 10000000)return x; 42 | } 43 | return "error\n"; 44 | } 45 | 46 | std::string concat_ostringstream() { 47 | print("ostringstream\n"); 48 | std::string a{ "a" }; 49 | std::string b{ "b" }; 50 | long n{}; 51 | while (++n) { 52 | std::stringstream x{}; 53 | x << a << ", " << b << "\n"; 54 | if (n >= 10000000)return x.str(); 55 | } 56 | return "error\n"; 57 | } 58 | 59 | std::string concat_format() { 60 | print("append_format\n"); 61 | std::string a{ "a" }; 62 | std::string b{ "b" }; 63 | long n{}; 64 | while (++n) { 65 | std::string x{}; 66 | x += std::format("{}, {}\n", a, b); 67 | if (n >= 10000000)return x; 68 | } 69 | return "error\n"; 70 | } 71 | 72 | int main() { 73 | timer(append_string); 74 | timer(concat_string); 75 | timer(concat_ostringstream); 76 | timer(concat_format); 77 | } -------------------------------------------------------------------------------- /src/7.5转换字符串.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | 3 | char char_upper(const char& c) { 4 | return static_cast(std::toupper(c)); 5 | } 6 | char char_lower(const char& c) { 7 | return static_cast(std::tolower(c)); 8 | } 9 | char rot13(const char& x) { 10 | auto rot13a = [](char x, char a)->char { 11 | return a + (x - a + 13) % 26; 12 | }; 13 | if (x >= 'A' && x <= 'Z')return rot13a(x, 'A'); 14 | if (x >= 'a' && x <= 'z')return rot13a(x, 'a'); 15 | return x; 16 | } 17 | std::string title_case(std::string& s) { 18 | auto begin{ s.begin() }; 19 | auto end{ s.end() }; 20 | *begin++ = char_upper(*begin); 21 | bool space_flag{ false }; 22 | for (auto it{ begin }; it != end; ++it) { 23 | if (*it == ' ')space_flag = true; 24 | else { 25 | if (space_flag)*it = char_upper(*it); 26 | space_flag = false; 27 | } 28 | } 29 | return s; 30 | } 31 | 32 | int main() { 33 | std::string s{ "hello jimi\n" }; 34 | print("{}", s); 35 | std::transform(s.begin(), s.end(), s.begin(), char_upper); 36 | print("{}", s); 37 | for (auto& c : s)c = rot13(c); 38 | print("{}", s); 39 | for (auto& c : s)c = rot13(char_lower(c)); 40 | print("{}", s); 41 | 42 | title_case(s); 43 | print("{}", s); 44 | } -------------------------------------------------------------------------------- /src/7.6使用格式库格式化文本.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | template 6 | struct Frac { 7 | T n; 8 | T d; 9 | }; 10 | template//十分简略,不支持很多操作 11 | struct std::formatter> { 12 | template 13 | constexpr auto parse(ParseContext& ctx) { 14 | return ctx.begin(); 15 | } 16 | template 17 | constexpr auto format(const Frac& f, FormatContext& ctx) const { 18 | return std::format_to(ctx.out(), "{0:d}/{1:d}", f.n, f.d); 19 | } 20 | }; 21 | 22 | template 23 | struct Frac2 { 24 | T n; 25 | T d; 26 | }; 27 | template 28 | struct std::formatter> { 29 | constexpr auto parse(auto& ctx) { 30 | m_fmt[m_buffer_len++] = '{'; 31 | auto iter = ctx.begin(); 32 | if (iter == ctx.end() || *iter == '}') { 33 | m_fmt[m_buffer_len++] = '}'; 34 | return iter; 35 | } 36 | m_fmt[m_buffer_len++] = ':'; 37 | for (; iter != ctx.end() && *iter != '}'; ++iter) 38 | m_fmt[m_buffer_len++] = *iter; 39 | m_fmt[m_buffer_len++] = '}'; 40 | return iter; 41 | } 42 | constexpr auto format(const Frac2& f, auto& ctx) const { 43 | std::string fmt{}; 44 | fmt += m_fmt, fmt += "/", fmt += m_fmt; 45 | auto iter = std::vformat_to(ctx.out(), fmt, std::make_format_args(f.n,f.d)); 46 | return iter; 47 | } 48 | private: 49 | char m_fmt[16]{}; 50 | size_t m_buffer_len = 0; 51 | }; 52 | 53 | int main() { 54 | const int a{ 47 }; 55 | const char* human{ "earthlings" }; 56 | const std::string_view alien{ "vulacans" }; 57 | const double df_pi{ std::numbers::pi }; 58 | const int inta{ 47 }; 59 | 60 | print("Hex: {0:x} Octal: {0:o} Decunak {0:d}\n", a); 61 | print("Hello {1} we are {0}\n", human, alien); 62 | 63 | print("π is {}\n", df_pi); 64 | print("π is {:.5}\n", df_pi); 65 | 66 | print("inta is [{:10}]\n", inta); 67 | print("inta is [{:<10}]\n", inta); 68 | print("inta is [{:>10}]\n", inta); 69 | 70 | print("inta is [{:*<10}]\n", inta); 71 | print("inta is [{:0>10}]\n", inta); 72 | 73 | print("inta is [{:^10}]\n", inta); 74 | print("inta is [{:_^10}]\n", inta); 75 | 76 | print("{:>8}: [{:04x}]\n", "Hex", inta); 77 | print("{:>8}: [{:4o}]\n", "Octal", inta); 78 | print("{:>8}: [{:4d}]\n", "Decimal", inta); 79 | 80 | Fracn{ 3,5 }; 81 | print("{}\n", n); 82 | //print("{:0x}\n", n);//error,因为我们的特化过于简单 83 | Frac2n2{ 10,5 }; 84 | print("{:0x}\n", n2); 85 | 86 | int array[] = { 1,2,3,4,5,6 }; 87 | std::vector v = { 122, 1222, 1222 }; 88 | print("{:0x}\n", v); 89 | print("{:0x}\n", array); 90 | } -------------------------------------------------------------------------------- /src/7.7删除字符串的空白.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | std::string trimstr(const std::string& s) { 5 | constexpr const char* whitespace{ " \t\r\n\v\f" }; 6 | if (s.empty())return s; 7 | const auto first{ s.find_first_not_of(whitespace) }; 8 | if (first == std::string::npos)return{}; 9 | const auto last{ s.find_last_not_of(whitespace) }; 10 | return s.substr(first, (last - first + 1)); 11 | } 12 | 13 | int main() { 14 | std::string s{ " \t ten-thumbed input \t \n \t" }; 15 | print("[{}]\n", s); 16 | print("[{}]\n", trimstr(s)); 17 | } -------------------------------------------------------------------------------- /src/7.8从用户输入中读取字符串.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | bool prompt(std::string_view s, std::string_view s2 = "") { 5 | if (s2.size())std::cout<> a >> b); prompt(p2)) { 45 | std::cout << "not numeric\n"; 46 | clearistream(); 47 | } 48 | std::cout << std::format("You netered {} and {}\n", a, b); 49 | std::cin.get(); 50 | 51 | line.clear(); 52 | prompt(p3); 53 | while (line.empty())std::getline(std::cin, line); 54 | std::stringstream ss(line); 55 | while (std::getline(ss, word, ',')) { 56 | if (word.empty())continue; 57 | std::cout << std::format("word: [{}]\n", trimstr(word)); 58 | } 59 | } -------------------------------------------------------------------------------- /src/7.9统计文件中的单词数.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | size_t wordcount(auto& is) { 6 | using it_t = std::istream_iterator; 7 | return std::distance(it_t{ is }, {}); 8 | } 9 | 10 | int main() { 11 | const char* fn{ "E:/自制视频教程/《C++20 STL Cookbook》2023/src/src/the-raven.txt" }; 12 | std::ifstream infile{ fn,std::ios_base::in }; 13 | size_t wc{ wordcount(infile) }; 14 | print("There are {} words in the file.\n", wc); 15 | print("size: {}\n", std::filesystem::file_size(fn)); 16 | } -------------------------------------------------------------------------------- /src/8.10共享管理对象的成员.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | struct animal { 6 | std::string name{}; 7 | std::string sound{}; 8 | animal(const std::string& n, const std::string& a) :name{ n }, sound{ a } { 9 | print("ctor: {}\n", name); 10 | } 11 | ~animal() { print("dtor: {}\n", name); } 12 | }; 13 | auto make_animal(const std::string& n, const std::string& s) { 14 | auto ap = std::make_shared(n, s); 15 | auto np = std::shared_ptr(ap, &ap->name);//这可以在不共享整个对象的情况下共享托管对象的一个 成员,并且在仍然使用该成员时不允许删除对象 16 | auto sp = std::shared_ptr(ap, &ap->sound);//并不会因为作用域结束就销毁 17 | print("Use count: name {}, sound {}\n", np.use_count(), sp.use_count());//3 3 18 | return std::tuple(np, sp);//因为别名指针 可以防止使用计数达到零,所以不会删除 19 | } 20 | int main() { 21 | auto [name,sound] = make_animal("Velociraptor", "Grrrr!"); 22 | print("The {} says {}\n", *name, *sound); 23 | print("Use count: name {}, sound {}\n", name.use_count(), sound.use_count());//2 2,那个函数里面的shared_ptr肯定还是销毁了的 24 | } -------------------------------------------------------------------------------- /src/8.11比较随机数引擎.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | constexpr size_t n_samples{ 1000 };//样本数量 6 | constexpr size_t n_partitions{ 10 };//分区数量 7 | constexpr size_t n_max{ 50 };//直方图图形条最大值 8 | 9 | template 10 | void histogram(const std::string_view& rng_name) { 11 | constexpr auto p_ratio =(double)RNG::max() / n_partitions; 12 | RNG rng{}; 13 | 14 | //收集样品 15 | std::vectorv(n_partitions); 16 | for (size_t i{}; i < n_samples; ++i) { 17 | ++v[(size_t)(rng() / p_ratio)]; 18 | } 19 | 20 | //显示直方图 21 | auto max_e1 = std::max_element(v.begin(), v.end()); 22 | auto v_ratio = *max_e1 / n_max;//不能超过最大,所以除一下 23 | if (v_ratio < 1)v_ratio = 1; 24 | std::cout << std::format("engine: {}\n", rng_name); 25 | for (size_t i{}; i < n_partitions; ++i) { 26 | std::cout << std::format("{:02}:{:*<{}}\n", i + 1, ' ', v[i]/v_ratio);//除是为了保证一个比例 27 | } 28 | endl(std::cout); 29 | } 30 | 31 | int main() { 32 | 33 | histogram("random_device"); 34 | histogram("default_random_engine"); 35 | 36 | histogram("minstd_rand0"); 37 | histogram("minstd_rand"); 38 | 39 | histogram("mt19937"); 40 | histogram("mt19937_64"); 41 | 42 | histogram("ranlux24_base"); 43 | histogram("ranlux48_base"); 44 | 45 | histogram("ranlux24"); 46 | histogram("ranlux48"); 47 | 48 | histogram("knuth_b"); 49 | } -------------------------------------------------------------------------------- /src/8.12比较随机数分布发生器.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | constexpr size_t n_samples{ 10000 }; 6 | constexpr size_t n_max{ 50 }; 7 | 8 | void dist_histogram(auto distor, const std::string_view& dist_name) { 9 | std::random_device seeds; 10 | std::default_random_engine rng(seeds());//随机数引擎 11 | std::mapm; 12 | 13 | //创建直方图 14 | for (size_t i{}; i < n_samples; ++i) { 15 | ++m[(long)distor(rng)]; 16 | } 17 | //打印直方图 18 | auto max_elm_it = std::max_element(m.begin(), m.end(), [](const auto& a, const auto& b) { 19 | return a.second < b.second; 20 | }); 21 | size_t max_elm = max_elm_it->second; 22 | size_t max_div = std::max(max_elm / n_max, size_t(1));//设置比例50 23 | std::cout << std::format("{}:\n", dist_name); 24 | for (const auto [randval, count] : m) { 25 | if (count < max_div)continue; 26 | std::cout << std::format("{:3}:{:*<{}}\n", randval, ' ', count / max_div); 27 | } 28 | } 29 | 30 | int main() { 31 | dist_histogram(std::uniform_int_distribution{0, 9}, "uniform_int_distribution"); 32 | dist_histogram(std::normal_distribution{0.0, 2.0}, "normal_distribution"); 33 | 34 | std::initializer_list intervals{ 0, 5, 10, 30 }; 35 | std::initializer_list weights{ 0.2, 0.3, 0.5 }; 36 | dist_histogram(std::piecewise_constant_distribution{begin(intervals), end(intervals), begin(weights)}, "piecewise_constant_distribution"); 37 | std::initializer_list weights2{ 0, 1, 1, 0 }; 38 | dist_histogram(std::piecewise_linear_distribution{begin(intervals), end(intervals), begin(weights2)}, "piecewise_linear_distribution"); 39 | 40 | dist_histogram(std::bernoulli_distribution{ 0.75 }, "bernoulli_distribution"); 41 | dist_histogram(std::discrete_distribution{ {1, 2, 4, 8}}, "discrete_distribution"); 42 | dist_histogram(std::binomial_distribution{10, 0.3}, "binomial_distribution"); 43 | dist_histogram(std::negative_binomial_distribution{10, 0.8}, "negative_binomial_distribution"); 44 | dist_histogram(std::geometric_distribution{0.4}, "geometric_distribution"); 45 | dist_histogram(std::exponential_distribution{0.4}, "exponential_distribution"); 46 | dist_histogram(std::gamma_distribution{1.5, 1.0}, "gamma_distribution"); 47 | dist_histogram(std::weibull_distribution{1.5, 1.0}, "weibull_distribution"); 48 | dist_histogram(std::extreme_value_distribution{0.0, 1.0}, "extreme_value_distribution"); 49 | dist_histogram(std::lognormal_distribution{0.5, 0.5}, "lognormal_distribution"); 50 | dist_histogram(std::chi_squared_distribution{1.0}, "chi_squared_distribution"); 51 | dist_histogram(std::cauchy_distribution{0.0, 0.1}, "cauchy_distribution"); 52 | dist_histogram(std::fisher_f_distribution{1.0, 1.0}, "fisher_f_distribution"); 53 | dist_histogram(std::student_t_distribution{1.0}, "student_t_distribution"); 54 | } -------------------------------------------------------------------------------- /src/8.2optional管理可选值.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | #if 0 5 | factor_t factor(long n) { 6 | struct factor_t { 7 | bool is_prime; 8 | long factor; 9 | }; 10 | factor_t r{}; 11 | for (long i = 2; i <= n / 2; ++i) { 12 | if (n % i == 0) { 13 | r.is_prime = false; 14 | r.factor = i; 15 | return r; 16 | } 17 | } 18 | r.is_prime = true; 19 | } 20 | #endif 21 | 22 | std::optionalfactor(long n) { 23 | for (long i = 2; i <= n / 2; ++i) { 24 | if (n % i == 0)return { i }; 25 | } 26 | return {}; 27 | } 28 | 29 | std::optional operator+(const std::optional& a, const std::optional& b) { 30 | if (a && b)return *a + *b; 31 | else return {}; 32 | } 33 | 34 | std::optional operator+(const std::optional& a, const int b) { 35 | if (a)return *a + b; 36 | else return {}; 37 | } 38 | 39 | int main() { 40 | long a{ 42 }; 41 | long b{ 73 }; 42 | auto x = factor(a); 43 | auto y = factor(b); 44 | if (x)print("lowest factor of {} is {} \n", a, *x); 45 | else print("{} is prime\n", a); 46 | if (y)print("lowest factor of {} is {} \n", a, *y); 47 | else print("{} is prime\n", b); 48 | 49 | std::optionala2{ 42 }; 50 | print("{}\n", *a2); 51 | if (a2)print("{}\n", *a2); 52 | else print("no value\n"); 53 | 54 | { 55 | std::optional a{ 42 }; 56 | std::optional b{ 73 }; 57 | auto sum{ a + b }; 58 | if (sum)print("{} + {} = {}\n", *a, *b, *sum); 59 | else print("NAN\n"); 60 | } 61 | 62 | (void)a2.has_value();//判断是否有值 63 | (void)a2.value();//和*作用一样,取值 64 | a2.reset();//销毁值,重置可选对象状态 65 | 66 | } -------------------------------------------------------------------------------- /src/8.3any保证类型安全.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | using namespace std::string_literals; 5 | 6 | void p_any(const std::any& a) { 7 | if (!a.has_value()) { 8 | print("None.\n"); 9 | } 10 | else if (a.type() == typeid(int)) { 11 | print("int: {}\n", std::any_cast(a)); 12 | } 13 | else if (a.type() == typeid(std::string)) { 14 | print("string: \"{}\"\n", std::any_cast(a)); 15 | } 16 | else if (a.type() == typeid(std::list)) { 17 | print("list: "); 18 | for (auto& i : std::any_cast&>(a)) { 19 | print("{} ", i); 20 | } 21 | print("\n"); 22 | } 23 | else { 24 | print("something else: {}\n", a.type().name()); 25 | } 26 | } 27 | 28 | int main() { 29 | std::any x{}; 30 | if (x.has_value())print("have value\n"); 31 | else print("no value\n"); 32 | 33 | x = 42; 34 | if (x.has_value()) { 35 | print("x has type :{}\n", x.type().name()); 36 | print("x has value: {}\n", std::any_cast(x)); 37 | } 38 | else { 39 | print("no value\n"); 40 | } 41 | 42 | x = "abc"s; 43 | print("x is type {} with value {}\n", x.type().name(), std::any_cast(x)); 44 | 45 | p_any( {} ); 46 | p_any(47); 47 | p_any("abc"s); 48 | p_any(std::list{ 1,2,3 }); 49 | p_any(std::vector{ 1,2,3 }); 50 | x.reset(); 51 | p_any(x); 52 | } -------------------------------------------------------------------------------- /src/8.4variant存储不同的类型.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | 6 | class Animal { 7 | std::string_view _name{}; 8 | std::string_view _sound{}; 9 | public: 10 | Animal(std::string_view n, std::string_view s) :_name{ n }, _sound{ s } {} 11 | void speak()const { 12 | print("{} says {}\n", _name, _sound); 13 | } 14 | void sound(std::string_view s) { 15 | _sound = s; 16 | } 17 | }; 18 | 19 | class Cat :public Animal { 20 | public: 21 | Cat(std::string_view n):Animal(n,"meow"){} 22 | }; 23 | class Dog :public Animal { 24 | public: 25 | Dog(std::string_view n) :Animal(n, "arf!"){} 26 | }; 27 | class Wookie :public Animal { 28 | public: 29 | Wookie(std::string_view n) :Animal(n, "grrraarrgghh!"){} 30 | }; 31 | 32 | struct animal_speaks { 33 | void operator()(const Dog& d)const { d.speak(); } 34 | void operator()(const Cat& c)const { c.speak(); } 35 | void operator()(const Wookie& w)const { w.speak(); } 36 | }; 37 | 38 | using v_animal = std::variant; 39 | int main() { 40 | std::listpets{ Cat{"Hobbes"},Dog{"Fido"},Cat{"Max"},Wookie{"Chewie"} }; 41 | for (const v_animal& a : pets) { 42 | std::visit(animal_speaks{}, a); 43 | } 44 | 45 | for (const v_animal& a : pets) { 46 | auto idx{ a.index() }; 47 | if (idx == 0)std::get(a).speak(); 48 | if (idx == 1)std::get(a).speak(); 49 | if (idx == 2)std::get(a).speak(); 50 | } 51 | 52 | for (const v_animal& a : pets) { 53 | if (const auto c{ std::get_if(&a) }; c) 54 | c->speak(); 55 | else if (const auto d{ std::get_if(&a) }; d) 56 | d->speak(); 57 | else if (const auto w{ std::get_if(&a) }; w) 58 | w->speak(); 59 | } 60 | 61 | size_t n_cats{}, n_dogs{}, n_wookies{}; 62 | for (const v_animal& a : pets) { 63 | if (std::holds_alternative(a))++n_cats; 64 | if (std::holds_alternative(a))++n_dogs; 65 | if (std::holds_alternative(a))++n_wookies; 66 | } 67 | print("there are {} cat(s),{} dog(s),and {} wookie(s)\n", n_cats, n_dogs, n_wookies); 68 | } -------------------------------------------------------------------------------- /src/8.5chrono的时间事件.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | using std::chrono::system_clock; 6 | using std::chrono::steady_clock; 7 | using std::chrono::high_resolution_clock; 8 | using std::chrono::duration; 9 | using seconds = duration; 10 | using milliseconds = duration; 11 | using microseconds = duration; 12 | using fps24 = duration>; 13 | 14 | constexpr uint64_t MAX_PRIME{ 0x1FFFF }; 15 | uint64_t count_primes() { 16 | constexpr auto is_prime = [](const uint64_t n) { 17 | for (uint64_t i{ 2 }; i < n / 2; ++i) { 18 | if (n % i == 0)return false; 19 | } 20 | return true; 21 | }; 22 | uint64_t count{ 0 }; 23 | uint64_t start{ 2 }; 24 | uint64_t end{ MAX_PRIME }; 25 | for (auto i{ start }; i < end; ++i) { 26 | if (is_prime(i))++count; 27 | } 28 | return count; 29 | } 30 | 31 | seconds timer(uint64_t(f)()) { 32 | auto t1{ steady_clock::now() }; 33 | uint64_t count{ f() }; 34 | auto t2{ steady_clock::now() }; 35 | seconds secs{ t2 - t1 }; 36 | print("there are {} primes in range\n", count); 37 | return secs; 38 | } 39 | 40 | int main() { 41 | auto t{ system_clock::now() }; 42 | print("system_clock::now is {:%F %T}\n", t); 43 | std::time_t now_t = system_clock::to_time_t(t); 44 | std::cout << "system_lock::now is " << std::put_time(localtime(&now_t), "%F %H:%M:%S") << '\n'; 45 | 46 | auto secs{ timer(count_primes) }; 47 | print("time elapsed: {:.3f} seconds\n", secs.count()); 48 | 49 | using fps24 = duration>; 50 | print("time elapsed: {:.3f} sec\n", secs.count()); 51 | print("time elapsed: {:.3f} ms\n", milliseconds(secs).count()); 52 | print("time elapsed: {:.3e} us\n", microseconds(secs).count()); 53 | print("time elapsed: {} frames at 24 fps\n", floor(secs).count());//其实差不多相当于前面sec的1/24,去除小数的 54 | } -------------------------------------------------------------------------------- /src/8.6对元组使用折叠表达式.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | template 6 | constexpr void print_t(const std::tuple& tup) { 7 | std::cout << "["; 8 | [&] (std::index_sequence) { 9 | (..., print((I != N - 1 ? "{}, " : "{}]"), std::get(tup))); 10 | }(std::make_index_sequence()); 11 | endl(std::cout); 12 | } 13 | 14 | template 15 | constexpr int sum_t(const std::tuple& tup)requires (std::integral&&...){ 16 | int accum{}; 17 | [&] (std::index_sequence) { 18 | (..., (accum += std::get(tup))); 19 | }(std::make_index_sequence()); 20 | return accum; 21 | } 22 | 23 | int main() { 24 | std::tuple t{ 123,1.234,"🥵" }; 25 | print_t(t); 26 | std::tuple t2{ 1,2,3,4,'a' }; 27 | print("sum: {}\n", sum_t(t2)); 28 | } -------------------------------------------------------------------------------- /src/8.7unique_ptr管理已分配内存.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | struct Thing { 5 | std::string thname{ "unk" }; 6 | Thing() { print("default ctor:{}\n", thname); } 7 | Thing(std::string n):thname(n) { print("param ctor:{}\n", thname); } 8 | ~Thing() { print("dtor :{}\n", thname); } 9 | }; 10 | 11 | void process_thing(const std::unique_ptr&p) { 12 | if (p)print("processing: {}\n", p->thname); 13 | else print("invalid pointer\n"); 14 | } 15 | 16 | struct Delete { 17 | void operator()(Thing* p) { 18 | print("自定义删除函数被调用\n"); 19 | delete p; 20 | } 21 | }; 22 | 23 | int main() { 24 | //std::unique_ptrpl{new Thing}; 25 | 26 | auto pl1 = std::make_unique("Thing 1"); 27 | process_thing(pl1); 28 | process_thing(std::make_unique("Thing 2")); 29 | 30 | //auto p2 = std::move(pl1); 31 | process_thing(pl1); 32 | pl1.reset(); 33 | process_thing(pl1); 34 | pl1.reset(new Thing("Thing 3")); 35 | process_thing(pl1); 36 | 37 | std::unique_ptrp2{ new Thing("🤣🤣"),Delete{} }; 38 | 39 | print("end of main()\n"); 40 | } -------------------------------------------------------------------------------- /src/8.8shared_ptr的共享对象.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | struct Thing { 5 | std::string thname{ "unk" }; 6 | Thing() { print("default ctor:{}\n", thname); } 7 | Thing(std::string n) :thname(n) { print("param ctor:{}\n", thname); } 8 | ~Thing() { print("dtor :{}\n", thname); } 9 | }; 10 | 11 | void check_thing_ptr(const std::shared_ptr& p) { 12 | if (p)print("{} use count: {}\n", p->thname, p.use_count()); 13 | else print("invalid pointer\n"); 14 | } 15 | 16 | int main() { 17 | std::shared_ptrp1{ new Thing("Thing 1") }; 18 | auto p2 = std::make_shared("Thing 2"); 19 | check_thing_ptr(p1); 20 | check_thing_ptr(p2); 21 | { 22 | auto pa = p1; 23 | auto pb = p1; 24 | auto pc = p1; 25 | auto pd = p1; 26 | check_thing_ptr(p1); 27 | check_thing_ptr(pa); 28 | check_thing_ptr(pb); 29 | check_thing_ptr(pc); 30 | check_thing_ptr(pd); 31 | } 32 | check_thing_ptr(p1); 33 | 34 | auto p3 = p1; 35 | check_thing_ptr(p1); 36 | p3.reset(); 37 | check_thing_ptr(p1); 38 | p1.reset(new Thing{ "🥵" }, [](Thing* p) { 39 | puts("自定义删除器被调用"); 40 | delete p; 41 | }); 42 | 43 | std::shared_ptrp4{ new Thing("Thing 4"),[](Thing* p) { 44 | puts("自定义删除器被调用!!!🤡🤡"); 45 | delete p; 46 | } }; 47 | } -------------------------------------------------------------------------------- /src/8.9对共享对象使用弱指针.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | 4 | struct Thing { 5 | std::string thname{ "unk" }; 6 | Thing() { print("default ctor:{}\n", thname); } 7 | Thing(std::string n) :thname(n) { print("param ctor:{}\n", thname); } 8 | ~Thing() { print("dtor :{}\n", thname); } 9 | }; 10 | void get_weak_thing(const std::weak_ptr& p) { 11 | if (auto sp = p.lock())print("{} use count: {}\n", sp->thname, sp.use_count()); 12 | else print("no shared object\n"); 13 | } 14 | 15 | struct circB; 16 | struct circA { 17 | std::shared_ptrp; 18 | ~circA() { print("dtor A\n"); } 19 | }; 20 | struct circB { 21 | std::weak_ptrp;//如果这里不使用weak_ptr而是shared_ptr,那么就会循环引用 22 | ~circB() { print("dtor B\n"); } 23 | }; 24 | 25 | std::shared_ptrp; 26 | 27 | int main() { 28 | auto thing1 = std::make_shared("Thing 1"); 29 | std::weak_ptrwp1; 30 | print("expried: {}\n", wp1.expired());//等价于use_cout()==0 31 | get_weak_thing(wp1); 32 | 33 | wp1 = thing1; 34 | get_weak_thing(wp1); 35 | 36 | std::weak_ptrwp2(thing1); 37 | get_weak_thing(wp2); 38 | 39 | thing1.reset(); 40 | get_weak_thing(wp1); 41 | get_weak_thing(wp2); 42 | 43 | auto a{ std::make_shared() }; 44 | auto b{ std::make_shared() }; 45 | a->p = b; 46 | b->p = a; 47 | //我们需要强调一点:weak_ptr是没有所有权的,指向shared_ptr不会增加use_count()的值,所以可以解决一些循环引用导致use_count()始终不为0无法析构的问题 48 | //即A内部有指向B,B内部有指向A,这样对于A,B必定是在A析构后B才析构,对于B,A必定是B析构后才析构A,这就是循环引用的问题,违反常规,导致内存泄露 49 | }// -------------------------------------------------------------------------------- /src/9.10实现多个生产者和消费者.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std::chrono_literals; 9 | 10 | constexpr auto delay_time{ 100ms }; 11 | constexpr auto consumer_wait{ 100ms };//持续时间,和条件变量一起使用 12 | constexpr size_t queue_limit{ 5 };//缓冲区限制,deque中最大容量值 13 | constexpr size_t num_items{ 15 };//生产者生产的最大产品数量 14 | constexpr size_t num_producers{ 3 };//生产者的数量 15 | constexpr size_t num_consumers{ 5 };//消费者的数量 16 | std::dequeqs{};//保存生成对象 17 | std::mutex q_mutex{};//锁 18 | std::condition_variable cv_producer{};//生产者条件变量 19 | std::condition_variable cv_consumer{};//消费者条件变量 20 | bool production_complete{};//标志位,所有生产者线程完毕的时候设置true 21 | 22 | void producer(const size_t id) { 23 | for (size_t i{}; i < num_items; ++i) { 24 | std::this_thread::sleep_for(delay_time * id); 25 | std::unique_lock lock{ q_mutex }; 26 | cv_producer.wait(lock, [&] {return qs.size() < queue_limit; }); 27 | qs.push_back(std::format("pid {}, qs {}, item {:02}\n", id, qs.size(), i + 1)); 28 | cv_consumer.notify_all();//生产完毕,唤醒消费者 29 | } 30 | } 31 | void consumer(const size_t id) { 32 | while (!production_complete) { 33 | std::unique_lock lock{ q_mutex }; 34 | cv_consumer.wait_for(lock,consumer_wait, [&] {return !qs.empty(); });//如果不使用wait_for,而是wait,那么根据main函数,生产者会先生产完,然后结束,设置标志位,那么消费者的wait的lambda永远不满足要求,且阻塞,无唤醒 35 | if (!qs.empty()) { 36 | std::cout << std::format("cid {}: {}", id,qs.front()); 37 | qs.pop_front(); 38 | } 39 | cv_producer.notify_all();//消费完毕,唤醒生产者 40 | } 41 | } 42 | 43 | int main() { 44 | std::list>producers;//生产者 45 | std::list>consumers;//消费者 46 | for (size_t i{}; i < num_producers; ++i) { 47 | producers.emplace_back(std::async(std::launch::async, producer, i)); 48 | } 49 | for (size_t i{}; i < num_consumers; i++) { 50 | consumers.emplace_back(std::async(std::launch::async, consumer, i)); 51 | } 52 | 53 | for (auto& f : producers)f.wait(); 54 | production_complete = true; 55 | /*qs.push_back("1"); 56 | qs.push_back("2"); 57 | qs.push_back("3"); 58 | qs.push_back("4"); 59 | qs.push_back("5"); 60 | cv_consumer.notify_all();*///如果消费者不使用wait_for,那么生产者结束后后,消费者的wait可能导致阻塞,往共享资源插入足够的元素,也可让它成功退出 61 | //我们的消费者线程数是5,所以插入5个,最为保险,确保每个线程都能运行退出,而不会卡在wait 62 | 63 | std::cout << "producers done.\n"; 64 | for (auto& f : consumers)f.wait(); 65 | std::cout << "consumbers done.\n"; 66 | } -------------------------------------------------------------------------------- /src/9.2休眠一定时间.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | using namespace std::this_thread; 4 | using namespace std::chrono_literals; 5 | 6 | int main() { 7 | auto t1 = std::chrono::steady_clock::now(); 8 | //print("sleep for 1.3 seconds\n"); 9 | sleep_for(1s + 300ms); 10 | //print("sleep for 2 seconds\n"); 11 | sleep_until(std::chrono::steady_clock::now() + 2s);//阻塞当前线程,直至抵达指定的 sleep_time,和前面的sleep_for不一样 12 | std::chrono::durationdur1 = std::chrono::steady_clock::now() - t1; 13 | print("total durtaion: {:.5}s\n", dur1.count()); 14 | } -------------------------------------------------------------------------------- /src/9.3thread实现并发.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | void sleepms(const unsigned ms) { 6 | using std::chrono::milliseconds; 7 | std::this_thread::sleep_for(milliseconds(ms)); 8 | } 9 | void fthread(const int n) { 10 | print("this is t{}\n", n); 11 | for (size_t i{}; i < 5; ++i) { 12 | sleepms(100 * n); 13 | print("t{}: {}\n", n, i + 1); 14 | } 15 | print("Finishing t{}\n", n); 16 | } 17 | 18 | int main() { 19 | std::thread t1(fthread, 1); 20 | t1.join(); 21 | 22 | std::thread t2(fthread, 2); 23 | t2.detach(); 24 | //sleepms(2000);//确保线程分离后的线程有足够的运行时间,这里其实写不写都行,因为它不是最后一行代码,如果不写,就可以看到它和t3的竞争了 25 | 26 | std::jthread t3(fthread, 3); 27 | print("end of main()\n"); 28 | } -------------------------------------------------------------------------------- /src/9.4async实现并发.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using secs = std::chrono::duration; 8 | 9 | struct prime_time { 10 | secs dur{};//计算花的时间 11 | uint64_t count{};//多少个质数 12 | }; 13 | prime_time count_prime(const uint64_t& max) { 14 | prime_time ret{}; 15 | constexpr auto isprime = [](const uint64_t& n) { 16 | for (uint64_t i{ 2 }; i < n / 2; ++i) { 17 | if (n % i == 0)return false; 18 | } 19 | return true; 20 | }; 21 | uint64_t start{ 2 }; 22 | uint64_t end{ max }; 23 | auto t1 = std::chrono::steady_clock::now(); 24 | for (uint64_t i{ start }; i <= end; ++i) { 25 | if (isprime(i))++ret.count; 26 | } 27 | ret.dur = std::chrono::steady_clock::now() - t1; 28 | return ret; 29 | } 30 | 31 | void f(std::promisevalue) { 32 | print("this is f()\n"); 33 | value.set_value(47); 34 | } 35 | 36 | int main() { 37 | constexpr uint64_t MAX_PRIME{ 0x1FFFF }; 38 | auto primes1 = std::async(count_prime, MAX_PRIME); 39 | auto pt = primes1.get(); 40 | print("primes: {} {:.3}\n", pt.count, pt.dur); 41 | 42 | std::list>swarm; 43 | print("start parallel primes\n"); 44 | auto t1{ std::chrono::steady_clock::now() }; 45 | for (size_t i{}; i < 15; ++i) { 46 | swarm.emplace_back(std::async(std::launch::async, count_prime, MAX_PRIME)); 47 | } 48 | for (size_t i{}; auto& f : swarm) { 49 | auto pt = f.get(); 50 | print("primes({:02}): {} {:.5}\n", ++i, pt.count, pt.dur); 51 | } 52 | 53 | secs dur_total{ std::chrono::steady_clock::now() - t1 }; 54 | print("total duration: {:.5}s\n", dur_total.count()); 55 | 56 | std::promisevalue_promise; 57 | std::futurevalue_future = value_promise.get_future(); 58 | std::thread t2(f, std::move(value_promise));//不可以复制,只能移动,其实改一下函数的参数为引用,然后std::ref也行 59 | t2.detach(); 60 | print("value is {}\n", value_future.get()); 61 | 62 | print("end of main()\n"); 63 | } -------------------------------------------------------------------------------- /src/9.5STL算法与执行策略.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using dur_t = std::chrono::duration; 9 | int main() { 10 | std::vectorv(10 * 1000 * 1000); 11 | std::random_device rng; 12 | for (auto& i : v)i = rng() % 0xFFFF; 13 | auto mul2 = [](int n) {return n * 2; }; 14 | 15 | auto t1 = std::chrono::steady_clock::now(); 16 | std::transform(v.begin(), v.end(), v.begin(), mul2); 17 | dur_t dur1 = std::chrono::steady_clock::now() - t1; 18 | print("no policy: {:.3}ms\n", dur1.count()); 19 | 20 | auto t2 = std::chrono::steady_clock::now(); 21 | std::transform(std::execution::seq, v.begin(), v.end(), v.begin(), mul2); 22 | dur_t dur2 = std::chrono::steady_clock::now() - t2; 23 | print("std::execution::seq: {:.3}ms\n", dur2.count()); 24 | 25 | auto t3 = std::chrono::steady_clock::now(); 26 | std::transform(std::execution::par, v.begin(), v.end(), v.begin(), mul2); 27 | dur_t dur3 = std::chrono::steady_clock::now() - t3; 28 | print("std::execution::par: {:.3}ms\n", dur3.count()); 29 | 30 | auto t4 = std::chrono::steady_clock::now(); 31 | std::transform(std::execution::par_unseq, v.begin(), v.end(), v.begin(), mul2); 32 | dur_t dur4 = std::chrono::steady_clock::now() - t4; 33 | print("std::execution::par_unseq: {:.3}ms\n", dur4.count()); 34 | 35 | auto t5 = std::chrono::steady_clock::now(); 36 | std::sort(v.begin(), v.end()); 37 | dur_t dur5 = std::chrono::steady_clock::now() - t5; 38 | print("sort: {:.3}ms\n", dur5.count()); 39 | 40 | auto t6 = std::chrono::steady_clock::now(); 41 | std::sort(std::execution::par,v.begin(), v.end()); 42 | dur_t dur6 = std::chrono::steady_clock::now() - t6; 43 | print("sort: {:.3}ms\n", dur6.count()); 44 | 45 | auto t7 = std::chrono::steady_clock::now(); 46 | std::sort(std::execution::par_unseq, v.begin(), v.end()); 47 | dur_t dur7 = std::chrono::steady_clock::now() - t7; 48 | print("sort: {:.3}ms\n", dur7.count()); 49 | } -------------------------------------------------------------------------------- /src/9.6互斥锁和锁安全的共享数据.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::mutex animal_mutex; 9 | 10 | class Animal { 11 | using friend_t = std::list; 12 | std::string_view s_name{ "unk" }; 13 | friend_t l_friends{}; 14 | public: 15 | Animal() = delete; 16 | Animal(const std::string_view n) :s_name{n}{} 17 | bool operator==(const Animal& o)const { 18 | return s_name.data() == o.s_name.data(); 19 | } 20 | 21 | bool is_friend(const Animal& o)const { 22 | for (const auto& a : l_friends) { 23 | if (a == o)return true; 24 | } 25 | return false; 26 | } 27 | std::optionalfind_friend(const Animal& o)noexcept { 28 | for (auto it{ l_friends.begin() }; it != l_friends.end(); ++it) { 29 | if (*it == o)return it; 30 | } 31 | return {}; 32 | } 33 | void print()const noexcept { 34 | std::lock_guard l{ animal_mutex }; 35 | auto n_animals{ l_friends.size() }; 36 | ::print("Animal: {}, friends: ", s_name); 37 | if (!n_animals)::print("none"); 38 | else { 39 | for (auto n : l_friends) { 40 | std::cout << n.s_name; 41 | if (--n_animals)std::cout << ", "; 42 | } 43 | } 44 | endl(std::cout); 45 | } 46 | bool add_friend(Animal& o)noexcept { 47 | ::print("add_friend {} -> {}\n", s_name, o.s_name); 48 | if (*this == o)return false; 49 | std::lock_guard l(animal_mutex); 50 | if (!is_friend(o))l_friends.emplace_back(o);//无重复则插入 51 | if (!o.is_friend(*this))o.l_friends.emplace_back(*this); 52 | return true; 53 | } 54 | bool delete_friend(Animal& o)noexcept { 55 | ::print("delete_friend {} -> {}\n", s_name, o.s_name); 56 | if (*this == o)return false; 57 | std::lock_guard l{ animal_mutex }; 58 | if (auto it = find_friend(o))l_friends.erase(it.value()); 59 | if (auto it = o.find_friend(*this))o.l_friends.erase(it.value()); 60 | return true; 61 | } 62 | }; 63 | 64 | int main() { 65 | auto cat1 = std::make_unique("Felix"); 66 | auto tiger1 = std::make_unique("Hobbes"); 67 | auto dog1 = std::make_unique("Astro"); 68 | auto rabbit1 = std::make_unique("Bugs"); 69 | 70 | auto a1 = std::async([&] {cat1->add_friend(*tiger1); }); 71 | auto a2 = std::async([&] {tiger1->add_friend(*rabbit1); }); 72 | auto a3 = std::async([&] {dog1->add_friend(*dog1); }); 73 | auto a4 = std::async([&] {rabbit1->add_friend(*cat1); }); 74 | a1.wait(); 75 | a2.wait(); 76 | a3.wait(); 77 | a4.wait(); 78 | 79 | auto p1 = std::async([&] {cat1->print(); }); 80 | auto p2 = std::async([&] {tiger1->print(); }); 81 | auto p3 = std::async([&] {dog1->print(); }); 82 | auto p4 = std::async([&] {rabbit1->print(); }); 83 | p1.wait(); 84 | p2.wait(); 85 | p3.wait(); 86 | p4.wait(); 87 | 88 | auto a5 = std::async([&] {cat1->delete_friend(*rabbit1); }); 89 | a5.wait(); 90 | auto p5 = std::async([&] {cat1->print(); }); 91 | auto p6 = std::async([&] {rabbit1->print(); }); 92 | } -------------------------------------------------------------------------------- /src/9.7atomic共享标志和值.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | 5 | std::atomicready{}; 6 | std::atomicg_count{}; 7 | std::atomic_flag winner{}; 8 | constexpr int max_count{ 1000 * 1000 }; 9 | constexpr int max_threads{ 100 }; 10 | 11 | struct Trivial { 12 | int a; 13 | int b; 14 | }; 15 | std::atomictrival; 16 | 17 | void countem(int id) { 18 | while (!ready)std::this_thread::yield();//让当前线程放弃CPU时间片,给其他线程 19 | for (int i{}; i < max_count; ++i)++g_count; 20 | if (!winner.test_and_set()) { 21 | std::cout << std::format("thread {:02} won!\n", id); 22 | } 23 | } 24 | std::string make_commas(const uint64_t& num) { 25 | std::string s{ std::to_string(num) }; 26 | for (long l = s.length() - 3; l > 0; l -= 3) { 27 | s.insert(l, ","); 28 | } 29 | return s; 30 | } 31 | 32 | int main() { 33 | std::vectorswarm; 34 | std::cout << std::format("spawn {} threads\n", max_threads); 35 | for (int i{}; i < max_threads; i++) { 36 | swarm.emplace_back(countem, i); 37 | } 38 | ready = true;//启动线程开始运行 39 | for (auto& t : swarm)t.join(); 40 | std::cout << std::format("global count: {}\n", make_commas(g_count)); 41 | 42 | std::cout << std::format("is g_count lock-free? {}\n", g_count.is_lock_free()); 43 | } -------------------------------------------------------------------------------- /src/9.8call_once初始化线程.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | 6 | constexpr size_t max_threads{ 25 }; 7 | std::once_flag init_flag; 8 | void do_init(size_t id) {//只会被调用一次 9 | print("do_init ({}):", id); 10 | } 11 | void do_print(size_t id) { 12 | std::call_once(init_flag, do_init, id); 13 | print("{} ", id); 14 | } 15 | 16 | int main() { 17 | std::listspawn; 18 | for (size_t id = 0; id < max_threads; id++){ 19 | spawn.emplace_back(do_print, id); 20 | } 21 | for (auto& t : spawn)t.join(); 22 | std::cout << '\n'; 23 | } -------------------------------------------------------------------------------- /src/9.9condition_variable解决生产者-消费者问题.cpp: -------------------------------------------------------------------------------- 1 | #include"print.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std::chrono_literals; 7 | 8 | constexpr size_t num_items{ 10 }; 9 | constexpr auto delay_time{ 200ms }; 10 | std::dequeq{}; 11 | std::mutex mtx{};//共用这一个锁 12 | std::condition_variable cond{}; 13 | bool finished{}; 14 | 15 | void producer() { 16 | for (size_t i{}; i < num_items; ++i) { 17 | std::this_thread::sleep_for(delay_time);//如果不延时,生产者运行太快,有可能直接运行完,把标志位都设置成true了,那么消费者不会打印任何数据 18 | std::lock_guard x{ mtx }; 19 | q.push_back(i); 20 | cond.notify_all();//唤醒 21 | } 22 | std::lock_guard x{ mtx }; 23 | finished = true; 24 | cond.notify_all(); 25 | } 26 | void consumer() { 27 | while (!finished) { 28 | std::unique_lock lck{ mtx };//lock() 29 | cond.wait(lck, [] {return !q.empty() || finished; });//unlock(),阻塞当前线程 唤醒之后会先上锁 30 | //while (!q.empty()) { 31 | std::cout << std::format("Got {} from the queue\n", q.front()); 32 | q.pop_front(); 33 | //} 34 | } 35 | } 36 | 37 | int main() { 38 | std::thread t1{ producer }; 39 | std::thread t2{ consumer }; 40 | t1.join(); 41 | t2.join(); 42 | std::cout << "finished!\n"; 43 | } -------------------------------------------------------------------------------- /src/cities.txt: -------------------------------------------------------------------------------- 1 | Las Vegas 2 | 661903 36.1699 -115.1398 3 | New York City 4 | 8850000 40.7128 -74.0060 5 | Berlin 6 | 3571000 52.5200 13.4050 7 | Mexico City 8 | 21900000 19.4326 -99.1332 9 | Sydney 10 | 5312000 -33.8688 151.2093 -------------------------------------------------------------------------------- /src/print.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | template < typename... Args> 10 | void print(const std::string_view fmt_str, Args&&... args) { 11 | auto fmt_args{ std::make_format_args(args...) }; 12 | std::string outstr{ std::vformat(fmt_str, fmt_args) }; 13 | fputs(outstr.c_str(), stdout); 14 | } 15 | 16 | template 17 | concept ContainerChecker = requires (const Container & c) {//与std::ranges::range等价 18 | std::ranges::begin(c); 19 | std::ranges::end(c); 20 | }; 21 | 22 | template 23 | struct std::formatter { 24 | constexpr auto format(const Ranges& rg, auto& format_context) { 25 | auto iter = std::format_to(format_context.out(), "{}", '[');//相当于先往format_context插入一个'[',使用的{}格式化的方式,并且会返回末尾迭代器,后面都将操作它 26 | auto begin = std::ranges::begin(rg); 27 | auto end = std::ranges::end(rg); 28 | std::basic_string_view fmt(m_fmt, m_fmt + m_buffer_len);//使用数据成员字符数组来构造一个string_view,使其拥有和字符数组一样的数据 29 | for (auto vec_iter = begin; vec_iter != end; ++vec_iter) { 30 | if (vec_iter != begin) {//第一次是==begin的,不会执行,后面会执行 31 | iter = ',', iter = ' ';//看似是给iter重复赋值,实际上它会自己往后增加,相当于往插入迭代器插入了','和' ' 32 | } 33 | iter = std::vformat_to(format_context.out(), fmt, std::make_format_args(*vec_iter));//将一个元素插入到format_context,返回末尾迭代器 34 | } 35 | iter = ']';//相当于再插入了一个']' 36 | return iter; 37 | } 38 | constexpr auto parse(auto& context) {//将会先调用parse成员函数,得到正确的格式化字符串再由format使用 39 | m_fmt[m_buffer_len++] = '{';//先放入一个'{' 40 | auto iter = context.begin(); 41 | if (iter == context.end() || *iter == '}') { 42 | m_fmt[m_buffer_len++] = '}'; 43 | return iter; 44 | } 45 | m_fmt[m_buffer_len++] = ':';//如果上一步没return 退出,也就是不是单纯的{},那么就需要给一个:,在这里相当于已经插入了{: 46 | for (; iter != context.end() && *iter != '}'; ++iter) { 47 | m_fmt[m_buffer_len++] = *iter; 48 | } 49 | m_fmt[m_buffer_len++] = '}';//最后放入'}' 50 | return iter; 51 | } 52 | private: 53 | CharT m_fmt[16]{}; //存储格式化字符串的缓冲区 54 | size_t m_buffer_len = 0; 55 | }; 56 | 57 | template 58 | concept Tuple = requires (T v) { 59 | [] (const std::tuple&tup) {}(v); 60 | }; 61 | 62 | template 63 | struct std::formatter { 64 | using fmt_str_t = std::basic_string; 65 | 66 | constexpr auto parse(auto& ctx) { 67 | auto ictx = std::begin(ctx);//值得注意的是ctx并不包含前面的{或:之类的,直接就是格式字符,这也是下面用于构造string_view的原因 68 | auto ectx = std::end(ctx); 69 | while (true) { 70 | auto rbra = std::find_if(ictx, ectx, [](auto v) {return v == '}' | v == '|'; }); 71 | auto viewt = std::vector>{ "{:", {ictx, rbra}, "}" } | std::views::join; 72 | m_fmt.push_back(fmt_str_t(std::begin(viewt), std::end(viewt))); // wish for std::ranges::to 73 | if (rbra != ectx && *rbra != '}') ictx = rbra + 1; 74 | else { return rbra; } 75 | } 76 | } 77 | constexpr auto format(Tuple auto& rg, auto& ctx) const { 78 | constexpr int N = std::tuple_size_v>; 79 | auto iter = std::format_to(ctx.out(), "{}", '['); 80 | auto fmt_iter = std::begin(m_fmt); 81 | auto fmt_end = std::end(m_fmt); 82 | const auto empty = std::string{ "{}" }; 83 | [&] (const TupleType & rg) { 84 | [&] (std::index_sequence) { 85 | (..., ( 86 | iter = std::vformat_to(ctx.out(), 87 | fmt_iter != fmt_end ? *(fmt_iter++) : empty, // if there is more tuple elements than fmt args, use "{}" for those missing fmt 88 | std::make_format_args(std::get(rg)) 89 | ), I + 1 != N ? iter = ' ' : iter = ']')); 90 | }(std::make_index_sequence()); 91 | }(rg); 92 | return iter; 93 | } 94 | private: 95 | std::vector m_fmt; 96 | }; 97 | 98 | namespace fs = std::filesystem; 99 | template<> 100 | struct std::formatter { 101 | template 102 | constexpr auto parse(ParseContext& ctx) { 103 | return ctx.begin(); 104 | } 105 | template 106 | auto format(const fs::path& p, FormatContext& ctx) { 107 | return std::format_to(ctx.out(), "{}", p.string()); 108 | } 109 | }; 110 | 111 | void print(std::ranges::range auto v){ 112 | print("size: {} ", v.size()); 113 | print("[ "); 114 | for (const auto& i : v)print("{} ", i); 115 | print("]\n"); 116 | } 117 | 118 | template 119 | void print(const std::map& map) { 120 | print("size: {} ", map.size()); 121 | print("[ "); 122 | for (auto& [k, v] : map)print("{}:{} ", k, v); 123 | print("]\n"); 124 | } 125 | 126 | template 127 | void rprint(std::multimap& todo) { 128 | for (const auto& i : todo | std::views::reverse) { 129 | print("{}: {}\n", i.first, i.second); 130 | } 131 | print("\n"); 132 | } 133 | 134 | void printc(const std::ranges::range auto& v, std::string_view s = "") { 135 | if (s.size())print("{}: ", s); 136 | for (const auto& i : v)print("[{}] ", i); 137 | print("\n"); 138 | } 139 | 140 | void printr(const auto& r, std::string_view s = "") { 141 | auto rbegin = std::rbegin(r); 142 | auto rend = std::rend(r); 143 | for (auto it = rbegin; it != rend; ++it) { 144 | print("{} ", *it); 145 | } 146 | print("\n"); 147 | } -------------------------------------------------------------------------------- /src/t.txt: -------------------------------------------------------------------------------- 1 | 1,2,3,4,5 -------------------------------------------------------------------------------- /src/test.ixx: -------------------------------------------------------------------------------- 1 | module; 2 | #define PI 3.14 3 | 4 | export module test; 5 | export import; 6 | export import test2; 7 | 8 | namespace mylib { 9 | 10 | export auto add(std::integral auto a, std::integral auto b) { 11 | return a + b; 12 | } 13 | 14 | auto print(auto t) { 15 | std::cout << t << '\n'; 16 | } 17 | } -------------------------------------------------------------------------------- /src/test2.ixx: -------------------------------------------------------------------------------- 1 | export module test2; 2 | import; 3 | 4 | export void t() { 5 | std::cout << "乐\n"; 6 | } -------------------------------------------------------------------------------- /src/the-end.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The End 5 | 35 | 36 | 37 | 38 |

You have reached the end of the Internet.

39 |

We hope you have enjoyed your experience.

40 |

Now go outside and play.

41 | 42 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/the-raven.txt: -------------------------------------------------------------------------------- 1 | Once upon a midnight dreary, while I pondered, weak and weary, 2 | Over many a quaint and curious volume of forgotten lore— 3 | While I nodded, nearly napping, suddenly there came a tapping, 4 | As of some one gently rapping, rapping at my chamber door— 5 | "'Tis some visitor," I muttered, "tapping at my chamber door— 6 | Only this and nothing more." 7 | 8 | Ah, distinctly I remember it was in the bleak December; 9 | And each separate dying ember wrought its ghost upon the floor. 10 | Eagerly I wished the morrow;—vainly I had sought to borrow 11 | From my books surcease of sorrow—sorrow for the lost Lenore— 12 | For the rare and radiant maiden whom the angels name Lenore— 13 | Nameless here for evermore. 14 | 15 | And the silken, sad, uncertain rustling of each purple curtain 16 | Thrilled me—filled me with fantastic terrors never felt before; 17 | So that now, to still the beating of my heart, I stood repeating, 18 | "'Tis some visitor entreating entrance at my chamber door— 19 | Some late visitor entreating entrance at my chamber door;— 20 | This it is and nothing more." 21 | 22 | Presently my soul grew stronger; hesitating then no longer, 23 | "Sir," said I, "or Madam, truly your forgiveness I implore; 24 | But the fact is I was napping, and so gently you came rapping, 25 | And so faintly you came tapping, tapping at my chamber door, 26 | That I scarce was sure I heard you"—here I opened wide the door;— 27 | Darkness there and nothing more. 28 | 29 | Deep into that darkness peering, long I stood there wondering, fearing, 30 | Doubting, dreaming dreams no mortal ever dared to dream before; 31 | But the silence was unbroken, and the stillness gave no token, 32 | And the only word there spoken was the whispered word, "Lenore?" 33 | This I whispered, and an echo murmured back the word, "Lenore!"— 34 | Merely this and nothing more. 35 | 36 | Back into the chamber turning, all my soul within me burning, 37 | Soon again I heard a tapping somewhat louder than before. 38 | "Surely," said I, "surely that is something at my window lattice; 39 | Let me see, then, what thereat is, and this mystery explore— 40 | Let my heart be still a moment and this mystery explore;— 41 | 'Tis the wind and nothing more!" 42 | 43 | Open here I flung the shutter, when, with many a flirt and flutter, 44 | In there stepped a stately Raven of the saintly days of yore; 45 | Not the least obeisance made he; not a minute stopped or stayed he; 46 | But, with mien of lord or lady, perched above my chamber door— 47 | Perched upon a bust of Pallas just above my chamber door— 48 | Perched, and sat, and nothing more. 49 | 50 | Then this ebony bird beguiling my sad fancy into smiling, 51 | By the grave and stern decorum of the countenance it wore, 52 | "Though thy crest be shorn and shaven, thou," I said, "art sure no craven, 53 | Ghastly grim and ancient Raven wandering from the Nightly shore— 54 | Tell me what thy lordly name is on the Night's Plutonian shore!" 55 | Quoth the Raven "Nevermore." 56 | 57 | Much I marvelled this ungainly fowl to hear discourse so plainly, 58 | Though its answer little meaning—little relevancy bore; 59 | For we cannot help agreeing that no living human being 60 | Ever yet was blest with seeing bird above his chamber door— 61 | Bird or beast upon the sculptured bust above his chamber door, 62 | With such name as "Nevermore." 63 | 64 | But the Raven, sitting lonely on the placid bust, spoke only 65 | That one word, as if his soul in that one word he did outpour. 66 | Nothing further then he uttered—not a feather then he fluttered— 67 | Till I scarcely more than muttered "Other friends have flown before— 68 | On the morrow he will leave me, as my hopes have flown before." 69 | Then the bird said "Nevermore." 70 | 71 | Startled at the stillness broken by reply so aptly spoken, 72 | "Doubtless," said I, "what it utters is its only stock and store 73 | Caught from some unhappy master whom unmerciful Disaster 74 | Followed fast and followed faster till his songs one burden bore— 75 | Till the dirges of his Hope that melancholy burden bore 76 | Of 'Never—nevermore.'" 77 | 78 | But the Raven still beguiling my sad fancy into smiling, 79 | Straight I wheeled a cushioned seat in front of bird, and bust and door; 80 | Then, upon the velvet sinking, I betook myself to linking 81 | Fancy unto fancy, thinking what this ominous bird of yore— 82 | What this grim, ungainly, ghastly, gaunt and ominous bird of yore 83 | Meant in croaking "Nevermore." 84 | 85 | This I sat engaged in guessing, but no syllable expressing 86 | To the fowl whose fiery eyes now burned into my bosom's core; 87 | This and more I sat divining, with my head at ease reclining 88 | On the cushion's velvet lining that the lamp-light gloated o'er, 89 | But whose velvet violet lining with the lamp-light gloating o'er, 90 | She shall press, ah, nevermore! 91 | 92 | Then, methought, the air grew denser, perfumed from an unseen censer 93 | Swung by Seraphim whose foot-falls tinkled on the tufted floor. 94 | "Wretch," I cried, "thy God hath lent thee—by these angels he hath sent thee 95 | Respite—respite and nepenthe, from thy memories of Lenore; 96 | Quaff, oh quaff this kind nepenthe and forget this lost Lenore!" 97 | Quoth the Raven "Nevermore." 98 | 99 | "Prophet!" said I, "thing of evil!—prophet still, if bird or devil!— 100 | Whether Tempter sent, or whether tempest tossed thee here ashore, 101 | Desolate yet all undaunted, on this desert land enchanted— 102 | On this home by Horror haunted—tell me truly, I implore— 103 | Is there—is there balm in Gilead?—tell me—tell me, I implore!" 104 | Quoth the Raven "Nevermore." 105 | 106 | "Prophet!" said I, "thing of evil—prophet still, if bird or devil! 107 | By that Heaven that bends above us—by that God we both adore— 108 | Tell this soul with sorrow laden if, within the distant Aidenn, 109 | It shall clasp a sainted maiden whom the angels name Lenore— 110 | Clasp a rare and radiant maiden whom the angels name Lenore." 111 | Quoth the Raven "Nevermore." 112 | 113 | "Be that word our sign in parting, bird or fiend!" I shrieked, upstarting— 114 | "Get thee back into the tempest and the Night's Plutonian shore! 115 | Leave no black plume as a token of that lie thy soul hath spoken! 116 | Leave my loneliness unbroken!—quit the bust above my door! 117 | Take thy beak from out my heart, and take thy form from off my door!" 118 | Quoth the Raven "Nevermore." 119 | 120 | And the Raven, never flitting, still is sitting, still is sitting 121 | On the pallid bust of Pallas just above my chamber door; 122 | And his eyes have all the seeming of a demon's that is dreaming, 123 | And the lamp-light o'er him streaming throws his shadow on the floor; 124 | And my soul from out that shadow that lies floating on the floor 125 | Shall be lifted—nevermore! -------------------------------------------------------------------------------- /交流/README.md: -------------------------------------------------------------------------------- 1 | ## 此目录用于提供存放提交者遇到的一些问题和有趣的代码,记得提交之前创建个人文件夹 --------------------------------------------------------------------------------