{"id":13645473,"url":"https://github.com/mpark/patterns","last_synced_at":"2025-05-15T12:05:10.169Z","repository":{"id":41253056,"uuid":"84391770","full_name":"mpark/patterns","owner":"mpark","description":"This is an experimental library that has evolved to P2688","archived":false,"fork":false,"pushed_at":"2024-11-27T23:38:37.000Z","size":252,"stargazers_count":673,"open_issues_count":1,"forks_count":31,"subscribers_count":28,"default_branch":"master","last_synced_at":"2025-04-14T22:18:34.517Z","etag":null,"topics":["pattern-matching"],"latest_commit_sha":null,"homepage":"https://wg21.link/p2688","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mpark.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":"support/single-header.py","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-03-09T03:03:43.000Z","updated_at":"2025-04-14T12:34:28.000Z","dependencies_parsed_at":"2024-12-21T19:01:27.312Z","dependency_job_id":"00db34ad-70f0-4152-aab7-e2fcbbbe0fb4","html_url":"https://github.com/mpark/patterns","commit_stats":{"total_commits":122,"total_committers":4,"mean_commits":30.5,"dds":"0.032786885245901676","last_synced_commit":"b3270e0dd7b6312f7a4fe8647e2333dbb86e355e"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpark%2Fpatterns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpark%2Fpatterns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpark%2Fpatterns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpark%2Fpatterns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mpark","download_url":"https://codeload.github.com/mpark/patterns/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254337612,"owners_count":22054253,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pattern-matching"],"created_at":"2024-08-02T01:02:35.684Z","updated_at":"2025-05-15T12:05:10.080Z","avatar_url":"https://github.com/mpark.png","language":"C++","readme":"# MPark.Patterns\n\n\u003e This is an experimental library that has evolved to [P2688], being proposed for C++26.\n\n[P2688]: https://wg21.link/p2688\n\n[![release][badge.release]][release]\n[![travis][badge.travis]][travis]\n[![license][badge.license]][license]\n[![godbolt][badge.godbolt]][godbolt]\n[![wandbox][badge.wandbox]][wandbox]\n\n[badge.release]: https://img.shields.io/github/release/mpark/patterns.svg\n[badge.travis]: https://travis-ci.org/mpark/patterns.svg?branch=master\n[badge.license]: http://img.shields.io/badge/license-boost-blue.svg\n[badge.godbolt]: https://img.shields.io/badge/try%20it-on%20godbolt-222266.svg\n[badge.wandbox]: https://img.shields.io/badge/try%20it-on%20wandbox-5cb85c.svg\n\n[release]: https://github.com/mpark/patterns/releases/latest\n[travis]: https://travis-ci.org/mpark/patterns\n[license]: https://github.com/mpark/patterns/blob/master/LICENSE.md\n[godbolt]: https://godbolt.org/g/b7WTDt\n[wandbox]: https://wandbox.org/permlink/bm5oBKAuHoSucEYG\n\n## Introduction\n\n__MPark.Patterns__ is an experimental pattern matching library for __C++17__.\n\nIt determines whether a given value __matches__ a __pattern__ and, if it does,\n__binds__ the desired portions of the value to a __handler__.\n\nPattern matching has been introduced to many programming languages outside of\nthe functional world, and this library draws inspiration from languages such as\nHaskell, OCaml, Rust, Scala, and Swift.\n\n```cpp\n#include \u003ccstdio\u003e\n\n#include \u003cmpark/patterns.hpp\u003e\n\nvoid fizzbuzz() {\n  using namespace mpark::patterns;\n  for (int i = 1; i \u003c= 100; ++i) {\n    match(i % 3, i % 5)(\n        pattern(0, 0) = [] { std::printf(\"fizzbuzz\\n\"); },\n        pattern(0, _) = [] { std::printf(\"fizz\\n\"); },\n        pattern(_, 0) = [] { std::printf(\"buzz\\n\"); },\n        pattern(_, _) = [i] { std::printf(\"%d\\n\", i); });\n  }\n}\n\nint main() {\n  fizzbuzz();\n}\n```\n\n## Basic Syntax\n\n```cpp\nusing namespace mpark::patterns;\nIDENTIFIERS(\u003cidentifier\u003e...);  // optional\nmatch(\u003cexpr\u003e...)(\n    pattern(\u003cpattern\u003e...) = [](\u003cbinding\u003e...) { /* ... */ },\n    pattern(\u003cpattern\u003e...) = [](\u003cbinding\u003e...) { /* ... */ },\n    // ...\n);\n```\n\n## Types of Patterns\n\n### Expression Pattern\n\nAn _expression pattern_ matches if the value compares equal to\nthe given expression.\n\n#### Requirements\n\nGiven an expression `e` and a value `x`, `e == x` must be a valid expression.\n\n#### Syntax\n\n  - `\u003cexpr\u003e`\n\n#### Examples\n\n```cpp\nint factorial(int n) {\n  using namespace mpark::patterns;\n  return match(n)(pattern(0) = [] { return 1; },\n                  //      ^ expression\n                  pattern(_) = [n] { return n * factorial(n - 1); });\n}\n```\n\n### Arg Pattern\n\nAn _arg pattern_ matches any value, and __binds__ the value by passing it\nto the corresponding handler. This pattern can be repeated in a single pattern,\nand they match independent of each other.\n\n#### Requirements\n\nNone.\n\n#### Syntax\n\n  - `arg`\n  - `arg(\u003cpattern\u003e)`\n\n#### Examples\n\n```cpp\nint factorial(int n) {\n  using namespace mpark::patterns;\n  return match(n)(pattern(0) = [] { return 1; },\n                  pattern(arg) = [](auto n) { return n * factorial(n - 1); });\n                  //      ^^^ arg\n}\n```\n\n```cpp\nusing P = std::pair\u003cint, int\u003e;\nP p = {101, 202};\n\nusing namespace mpark::patterns;\nmatch(p)(pattern(arg(ds(101, _))) = [](P \u0026p) { std::cout \u003c\u003c \"pair!\\n\"; },\n         //      ^^^ pass the pair!\n         pattern(_) = [] { std::cout \u003c\u003c \"not a pair\\n\"; });\n// prints: \"pair!\"\n```\n\n### Wildcard Pattern\n\nA _wildcard pattern_ matches any value and __discards__ the value by __not__\npassing it to the corresponding handler. This pattern can be repeated within\na single pattern, and they match independent of each other.\n\n#### Requirements\n\nNone.\n\n#### Syntax\n\n  - `_` (underscore)\n\n#### Examples\n\n```cpp\nint factorial(int n) {\n  using namespace mpark::patterns;\n  return match(n)(pattern(0) = [] { return 1; },\n                  pattern(_) = [n] { return n * factorial(n - 1); });\n                  //      ^ wildcard\n}\n```\n\n### Identifier Pattern\n\nAn _identifier pattern_ is similar to `arg` and `_` in that it matches any value.\n\nTwo major differences are:\n  1. Ability to operate on __names__ rather than just `arg` or `_`.\n  2. When an identifier is repeated within a single pattern, the values bound\n     to the repeated identifiers must compare equal for the pattern to match.\n\nThere are two types of identifier patterns: __binding__ and __discarding__.\n\n#### Requirements\n\nIf no identifiers are repeated, none.\n\nOtherwise, let `x` be a repeated identifer and `v, vs...` be the group of values\nmatched by the repeated instances of `x`. Then `(... \u0026\u0026 (v == vs))` must be a\nvalid expression. The same requirement applies to any other repeated identifiers\nin a single pattern.\n\n#### Syntax\n\n  - `IDENTIFIERS(\u003cidentifier\u003e...);`\n  - `\u003cidentifier\u003e`\n  - `\u003cidentifier\u003e(\u003cpattern\u003e)`\n\nIf `\u003cidentifier\u003e` has a leading `_` (underscore), it is a __discarding__\nidentifier. Otherwise, it is a __binding__ identifier.\n\n#### Examples\n\n```cpp\nvoid is_same(int lhs, int rhs) {\n  using namespace mpark::patterns;\n  IDENTIFIERS(x, y);\n  match(lhs, rhs)(\n      pattern(x, x) = [](auto) { std::cout \u003c\u003c \"same\\n\"; },\n      //      ^  ^ binding identifier (repeated)\n      pattern(x, y) = [](auto, auto) { std::cout \u003c\u003c \"diff\\n\"; }\n      //      ^  ^ binding identifier\n  );\n}\n\nis_same(101, 101);  // prints: \"same\"\nis_same(101, 202);  // prints: \"diff\"\n```\n\n```cpp\nvoid is_same(int lhs, rhs) {\n  using namespace mpark::patterns;\n  IDENTIFIERS(_x, _y);\n  match(42, 42)(\n      pattern(_x, _x) = [] { std::cout \u003c\u003c \"same\\n\"; },\n      //      ^   ^ discarding identifier (repeated)\n      pattern(_x, _y) = [] { std::cout \u003c\u003c \"diff\\n\"; }\n      //      ^   ^ discarding identifier\n  );\n}\n\nis_same(101, 101);  // prints: \"same\"\nis_same(101, 202);  // prints: \"diff\"\n```\n\n```cpp\nstd::tuple\u003cint, int\u003e t = {101, 202};\nstd::optional\u003cint\u003e o = 101;\n\nusing namespace mpark::patterns;\nIDENTIFIERS(x, y);\nmatch(t, o)(\n    pattern(ds(x, x), some(x)) = [](auto x) {\n      std::cout \u003c\u003c \"They're all \" \u003c\u003c x \u003c\u003c \"!\\n\";\n    },\n    pattern(ds(x, y), some(x)) = [](auto x, auto y) {\n      std::cout \u003c\u003c \"I recognize x-y-x!\\n\";\n    },\n    pattern(_) = [] { std::cout \u003c\u003c \"I don't know.\\n\"; });\n// prints: \"I recognize x-y-x!\"\n```\n\n### Destructure Pattern\n\nA _destructure pattern_ matches values that hold multiple values.\n\n#### Requirements\n\nGiven a value `x` of type `T`, `T` must satisfy one of the following conditions:\n  1. `std::is_array_v\u003cT\u003e == true`, or\n  2. `std::is_class_v\u003cT\u003e == true` and `std::tuple_size\u003cT\u003e` is a complete type, or\n  3. `std::is_aggregate_v\u003cT\u003e == true`\n\nIf (2), the following conditions must also be satisfied.\n  - `std::tuple_size\u003cT\u003e::value` must be a well-formed\n    integer constant expression, and\n  - `x.get\u003cI\u003e()` or `get\u003cI\u003e(x)` must be a valid expression for all `I` in\n    `[0, std::tuple_size\u003cT\u003e::value)`\n\nFor aggregate types (3), the current implementation only supports types that\ncontain upto 16 non-static data members.\n\n__NOTE__: These requirements are very similar to the requirements for\n          [C++17 Structured Binding][structured-binding].\n\n[structured-binding]: http://en.cppreference.com/w/cpp/language/structured_binding\n\n#### Syntax\n\n  - `ds(\u003cpattern\u003e...)`\n\n#### Examples\n\n```cpp\nauto t = std::make_tuple(101, \"hello\", 1.1);\n\n// C++17 Structured Binding:\nconst auto \u0026 [x, y, z] = t;\n// ...\n\n// MPark.Patterns:\nusing namespace mpark::patterns;\nIDENTIFIERS(x, y, z);\nmatch(t)(\n    pattern(ds(x, y, z)) = [](auto \u0026\u0026x, auto \u0026\u0026y, auto \u0026\u0026z) { /* ... */ });\n    //      ^^^^^^^^^^^ destructure\n```\n\n__NOTE__: The top-level is wrapped by a `tuple`, allowing us to write:\n\n```cpp\nvoid fizzbuzz() {\n  for (int i = 1; i \u003c= 100; ++i) {\n    using namespace mpark::patterns;\n    match(i % 3, i % 5)(\n        pattern(0, 0) = [] { std::cout \u003c\u003c \"fizzbuzz\\n\"; },\n        pattern(0, _) = [] { std::cout \u003c\u003c \"fizz\\n\"; },\n        pattern(_, 0) = [] { std::cout \u003c\u003c \"buzz\\n\"; },\n        pattern(_, _) = [i] { std::cout \u003c\u003c i \u003c\u003c '\\n'; });\n  }\n}\n```\n\n### Optional Pattern\n\nAn _optional pattern_ matches values that can be dereferenced,\nand tested as a `bool`.\n\n#### Requirements\n\nGiven a value `x` of type `T`, `T` must satisfy all of the following conditions:\n  - `*x` is a valid expression, and\n  - `x` is contextually convertible to `bool`\n\n#### Syntax\n\n  - `some(\u003cpattern\u003e)`\n  - `none`\n\n#### Examples\n\n```cpp\nint *p = nullptr;\n\nusing namespace mpark::patterns;\nmatch(p)(pattern(some(_)) = [] { std::cout \u003c\u003c \"some\\n\"; },\n         pattern(none) = [] { std::cout \u003c\u003c \"none\\n\"; });\n// prints: \"none\"\n```\n\n```cpp\nstd::optional\u003cint\u003e o = 42;\n\nusing namespace mpark::patterns;\nmatch(o)(\n    pattern(some(arg)) = [](auto x) { std::cout \u003c\u003c \"some(\" \u003c\u003c x \u003c\u003c \")\\n\"; },\n    pattern(none) = [] { std::cout \u003c\u003c \"none\\n\"; });\n// prints: \"some(42)\"\n```\n\n### As Pattern\n\nAn _as pattern_ matches values that is capable of holding a value of multiple types.\n\n#### Requirements\n\nGiven a value `x` of type `T`, and a pattern `as\u003cU\u003e(\u003cpattern\u003e)`,\n`T` must satisfy one of the following conditions:\n  1. `std::is_polymorphic_v\u003cT\u003e == true`, or\n  2. `std::is_class_v\u003cT\u003e == true` and `std::variant_size\u003cT\u003e` is a complete type, or\n  3. `x.any_cast\u003cU\u003e()` or `any_cast\u003cU\u003e(\u0026x)` is a valid expression\n\n- If (1), `dynamic_cast\u003cU'\u003e(\u0026x)` must be a valid expression,\n  where `U'` is pointer to `U` with the same cv-qualifiers as `decltype(x)`\n- If (2), `x.get_if\u003cU\u003e()` or `get_if\u003cU\u003e(\u0026x)` must be a valid expression\n\n#### Syntax\n\n  - `as\u003cU\u003e(\u003cpattern\u003e)`\n\n#### Examples\n\n```cpp\nstruct Shape { virtual ~Shape() = default; };\nstruct Circle : Shape {};\nstruct Square : Shape {};\n\nstd::unique_ptr\u003cShape\u003e shape = std::make_unique\u003cSquare\u003e();\n\nusing namespace mpark::patterns;\nmatch(shape)(pattern(some(as\u003cCircle\u003e(_))) = [] { std::cout \u003c\u003c \"Circle\\n\"; },\n             pattern(some(as\u003cSquare\u003e(_))) = [] { std::cout \u003c\u003c \"Square\\n\"; });\n// prints: \"Square\"\n```\n\n```cpp\nusing str = std::string;\nstd::variant\u003cint, str\u003e v = 42;\n\nusing namespace mpark::patterns;\nmatch(v)(pattern(as\u003cint\u003e(_)) = [] { std::cout \u003c\u003c \"int\\n\"; },\n         pattern(as\u003cstr\u003e(_)) = [] { std::cout \u003c\u003c \"str\\n\"; });\n// prints: \"int\"\n```\n\n```cpp\nusing str = std::string;\nstd::any a = str(\"hello\");\n\nusing namespace mpark::patterns;\nmatch(a)(pattern(as\u003cint\u003e(_)) = [] { std::cout \u003c\u003c \"int\\n\"; },\n         pattern(as\u003cstr\u003e(_)) = [] { std::cout \u003c\u003c \"str\\n\"; });\n// prints: \"str\"\n```\n\n### Visit Pattern\n\nA _visit pattern_ matches values that is capable of holding a value of\nclosed set of types, and can be visited.\n\n#### Requirements\n\nGiven a value `x`, The following code must be valid.\n\n```\nusing std::visit;\nvisit([](auto \u0026\u0026) {}, x);`\n```\n\n#### Syntax\n\n  - `vis(\u003cpattern\u003e)`\n\n#### Examples\n\n```cpp\nusing str = std::string;\nstd::variant\u003cint, str\u003e v = \"hello world!\";\n\nstruct Visitor {\n  void operator()(int n) const { std::cout \u003c\u003c \"int: \" \u003c\u003c n \u003c\u003c '\\n'; }\n  void operator()(const str \u0026s) const { std::cout \u003c\u003c \"str: \" \u003c\u003c s \u003c\u003c '\\n'; }\n};\n\nusing namespace mpark::patterns;\nmatch(v)(pattern(vis(arg)) = Visitor{});\n// prints: \"str: hello world!\".\n```\n\n### Alternation Pattern\n\nAn _alternation pattern_ matches values that match any of the given patterns.\n\n#### Requirements\n\nNone.\n\n#### Syntax\n\n  - `anyof(\u003cpattern\u003e...)`\n\n#### Examples\n\n```cpp\nstd::string s = \"large\";\n\nusing namespace mpark::patterns;\nmatch(s)(\n    pattern(anyof(\"big\", \"large\", \"huge\")) = [] { std::cout \u003c\u003c \"big!\\n\"; },\n    pattern(anyof(\"little\", \"small\", \"tiny\")) = [] { std::cout \u003c\u003c \"small.\\n\"; },\n    pattern(_) = [] { std::cout \u003c\u003c \"unknown size.\\n\"; });\n```\n\n### Variadic Pattern\n\nA _variadic pattern_ matches 0 or more values that match a given pattern.\n\n#### Requirements\n\n  - A _variadic pattern_ can only appear within a destructure pattern.\n  - A _variadic pattern_ can only appear once.\n\n#### Syntax\n\n  - `variadic(\u003cpattern\u003e)`\n\n#### Examples\n\n```cpp\nauto x = std::make_tuple(101, \"hello\", 1.1);\n\nusing namespace mpark::patterns;\nmatch(x)(\n    pattern(ds(variadic(arg))) = [](const auto \u0026... xs) {\n      int dummy[] = { (std::cout \u003c\u003c xs \u003c\u003c ' ', 0)... };\n      (void)dummy;\n    });\n// prints: \"101 hello 1.1 \"\n```\n\nThis could also be used to implement [C++17 `std::apply`][apply]:\n\n[apply]: http://en.cppreference.com/w/cpp/utility/apply\n\n```cpp\ntemplate \u003ctypename F, typename Tuple\u003e\ndecltype(auto) apply(F \u0026\u0026f, Tuple \u0026\u0026t) {\n  using namespace mpark::patterns;\n  return match(std::forward\u003cT\u003e(t))(\n      pattern(ds(variadic(arg))) = std::forward\u003cF\u003e(f));\n}\n```\n\nand even [C++17 `std::visit`][visit]:\n\n[visit]: http://en.cppreference.com/w/cpp/utility/variant/visit\n\n```cpp\ntemplate \u003ctypename F, typename... Vs\u003e\ndecltype(auto) visit(F \u0026\u0026f, Vs \u0026\u0026... vs) {\n  using namespace mpark::patterns;\n  return match(std::forward\u003cVs\u003e(vs)...)(\n      pattern(variadic(vis(arg))) = std::forward\u003cF\u003e(f));\n}\n```\n\nWe can even get a little fancier:\n\n```cpp\nint x = 42;\nauto y = std::make_tuple(101, \"hello\", 1.1);\n\nusing namespace mpark::patterns;\nmatch(x, y)(\n    pattern(arg, ds(variadic(arg))) = [](const auto \u0026... xs) {\n      int dummy[] = { (std::cout \u003c\u003c xs \u003c\u003c ' ', 0)... };\n      (void)dummy;\n    });\n// prints: \"42 101 hello 1.1 \"\n```\n\n## Pattern Guards\n\nWhile pattern matching is very useful to match values against patterns,\nit mainly focuses on equality comparisons. Pattern guards are used to\ntest whether the bound values satisfy some predicate.\n\n### `WHEN`\n\nA `WHEN` clause appears inside the handler as the only expression.\nA `WHEN` clause differs from an `if` statement in that if the conditional\nexpression evaluates to `false`, the `WHEN` clause falls through to the\nnext case, whereas the `if` statement would stay in the handler.\n\n#### Requirements\n\nThe `WHEN` clause may only appear once inside the handler as the only\nexpression, and the conditional expression must be contextually\nconvertible to `bool`.\n\n#### Syntax\n\n  - `WHEN(\u003ccondition\u003e) { /* ... */ };`\n\n#### Examples\n\n```cpp\nusing namespace mpark::patterns;\nIDENTIFIERS(x, y);\nmatch(101, 202)(\n    pattern(x, x) = [](int) { std::cout \u003c\u003c \"EQ\\n\"; },\n    pattern(x, y) = [](int x, int y) { WHEN(x \u003e y) { std::cout \u003c\u003c \"GT\\n\"; }; },\n    pattern(x, y) = [](int x, int y) { WHEN(x \u003c y) { std::cout \u003c\u003c \"LT\\n\"; }; });\n// prints: \"LT\"\n```\n\n## Pattern Statements\n\n### `if_let`\n\nThis construct is simply syntactic sugar for the following situation:\n\n```cpp\nstd::optional\u003cint\u003e o = 42;\n\nusing namespace mpark::patterns;\nmatch(o)(\n    pattern(some(arg)) = [](auto x) { ... },\n    pattern(_) = [] {});\n```\n\nFor this situation, `if_let` provides a cleaner interface:\n\n```cpp\nstd::optional\u003cint\u003e o = 42;\n\nusing namespace mpark::patterns;\nif_let (pattern(some(arg)) = o) = [](auto x) {\n  // ...\n};\n```\n\n### `for_let`\n\nSuppose we want to match each element in a range-based `for` loop with pattern.\nWe could imagine being able to write something like:\n\n```cpp\nstd::vector\u003cstd::pair\u003cint, int\u003e\u003e pairs = {{0, 1}, {1, 1}, {0, 0}, {0, 2}};\n\nfor ((0, x) : pairs) {\n  std::cout \u003c\u003c x \u003c\u003c ' ';\n}\n// prints: \"1 0 2 \"\n```\n\nWith `if_let` we can say something close-ish:\n\n```cpp\nstd::vector\u003cstd::pair\u003cint, int\u003e\u003e pairs = {{0, 1}, {1, 1}, {0, 0}, {0, 2}};\n\nfor (const auto \u0026p : pairs) {\n  using namespace mpark::patterns;\n  if_let (pattern(ds(0, arg)) = p) = [](auto x) {\n    std::cout \u003c\u003c x \u003c\u003c ' ';\n  };\n}\n// prints: \"1 0 2 \"\n```\n\n`for_let` allows the above example to be written more concisely:\n\n```cpp\nstd::vector\u003cstd::pair\u003cint, int\u003e\u003e pairs = {{0, 1}, {1, 1}, {0, 0}, {0, 2}};\n\nusing namespace mpark::patterns;\nfor_let (pattern(ds(0, arg)) = pairs) = [](auto x) {\n  std::cout \u003c\u003c x \u003c\u003c ' ';\n};\n// prints: \"1 0 2 \"\n```\n\n`for_let` also provides the `break` and `continue` statements with\n`return Break;` and `return Continue;` respectively.\n\n```cpp\nstd::vector\u003cstd::pair\u003cint, int\u003e\u003e pairs = {{0, 1}, {1, 1}, {0, 0}, {0, 2}};\n\nusing namespace mpark::patterns;\nfor_let (pattern(ds(0, arg)) = pairs) = [](auto x) {\n  if (x == 1) return Break;\n  std::cout \u003c\u003c x \u003c\u003c ' ';\n  return Continue;\n};\n// prints: \"0 \"\n```\n\n```cpp\nstd::vector\u003cstd::pair\u003cint, int\u003e\u003e pairs = {{0, 1}, {1, 1}, {0, 0}, {0, 2}};\n\nusing namespace mpark::patterns;\nfor_let (pattern(ds(0, arg)) = pairs) = [](auto x) {\n  if (x == 0) return Continue;\n  std::cout \u003c\u003c x \u003c\u003c ' ';\n  return Continue;\n};\n// prints: \"1 2 \"\n```\n\n## Requirements\n\nThis library requires a standard conformant __C++17__ compiler.\nThe following compilers are continously tested:\n\n| Compiler    | Operating System   | Version String                                                               |\n|-------------|--------------------|------------------------------------------------------------------------------|\n| GCC 7.4.0   | Ubuntu 16.04.6 LTS | g++-7 (Ubuntu 7.4.0-1ubuntu1~16.04~ppa1) 7.4.0                               |\n| GCC 8.1.0   | Ubuntu 16.04.6 LTS | g++-8 (Ubuntu 8.1.0-5ubuntu1~16.04) 8.1.0                                    |\n| Clang 5.0.0 | Ubuntu 16.04.6 LTS | clang version 5.0.0-3~16.04.1 (tags/RELEASE_500/final)                       |\n| Clang 6.0.0 | Ubuntu 16.04.6 LTS | clang version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final)                |\n| Clang 7.1.0 | Ubuntu 16.04.6 LTS | clang version 7.1.0-svn353565-1~exp1~20190408084827.60 (branches/release_70) |\n\n## CMake Variables\n\n  -  __`MPARK_PATTERNS_INCLUDE_TESTS`__:`BOOL` (__default__: `OFF`)\n\n     Build tests.\n\n## Unit Tests\n\nRefer to [test/README.md](test/README.md).\n\n## License\n\nDistributed under the [Boost Software License, Version 1.0](LICENSE.md).\n\n## Related Work\n\n  - [solodon4/Mach7](https://github.com/solodon4/Mach7)\n  - [jbandela/simple_match](https://github.com/jbandela/simple_match/)\n  * [N3449: Open and Efficient Type Switch for C++](https://wg21.link/N3449)\n  * [P0144: Structured bindings](https://wg21.link/P0144)\n  - [P1260: Pattern Matching](https://wg21.link/P1260)\n  - [P1308: Pattern Matching](https://wg21.link/P1308)\n  - [P1371: Pattern Matching](https://wg21.link/P1371)\n  - [P2392: Pattern Matching using `is` and `as`](https://wg21.link/P2392)\n","funding_links":[],"categories":["C++"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpark%2Fpatterns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmpark%2Fpatterns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpark%2Fpatterns/lists"}