{"id":18747877,"url":"https://github.com/pthom/cleantype","last_synced_at":"2025-04-12T22:34:25.826Z","repository":{"id":40725963,"uuid":"162741489","full_name":"pthom/cleantype","owner":"pthom","description":"Readable and consistent C++ type introspection - Compiler Decipherer","archived":false,"fork":false,"pushed_at":"2019-03-21T12:05:11.000Z","size":1421,"stargazers_count":89,"open_issues_count":0,"forks_count":8,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-10T19:45:58.384Z","etag":null,"topics":["c-plus-plus","c-plus-plus-14","cpp","cpp14","functional-programming","header-only","library","reflection","type","types"],"latest_commit_sha":null,"homepage":"","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/pthom.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":null}},"created_at":"2018-12-21T17:34:33.000Z","updated_at":"2024-07-07T12:36:05.000Z","dependencies_parsed_at":"2022-08-18T21:42:43.843Z","dependency_job_id":null,"html_url":"https://github.com/pthom/cleantype","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pthom%2Fcleantype","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pthom%2Fcleantype/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pthom%2Fcleantype/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pthom%2Fcleantype/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pthom","download_url":"https://codeload.github.com/pthom/cleantype/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248642308,"owners_count":21138350,"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":["c-plus-plus","c-plus-plus-14","cpp","cpp14","functional-programming","header-only","library","reflection","type","types"],"created_at":"2024-11-07T16:31:48.359Z","updated_at":"2025-04-12T22:34:25.393Z","avatar_url":"https://github.com/pthom.png","language":"C++","readme":"\n# Table of content\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003e\n\u003cp style=\"text-align: left;\"\u003e\n   \u003ca href=\"#CleanType-Readable-C++-type-introspection---Compiler-Decipherer\"\u003eCleanType: Readable C++ type introspection - Compiler Decipherer\u003c/a\u003e\u003cbr/\u003e\n   \u003ca href=\"#Installation-and-usage\"\u003eInstallation and usage\u003c/a\u003e\u003cbr/\u003e\n   \u003ca href=\"#About-this-manual\"\u003eAbout this manual\u003c/a\u003e\u003cbr/\u003e\n   \u003ca href=\"#Readable-type-names-and-full-type-names\"\u003eReadable type names and full type names\u003c/a\u003e\u003cbr/\u003e\n   \u003ca href=\"#Decipher-compiler-output-and-identify-types-in-the-compiler-output\"\u003eDecipher compiler output and identify types in the compiler output\u003c/a\u003e\u003cbr/\u003e\n   \u003ca href=\"#Identify-the-auto-return-type-of-functions-and-functors\"\u003eIdentify the auto return type of functions and functors\u003c/a\u003e\u003cbr/\u003e\n   \u003ca href=\"#Identify-the-signature-of-lambdas\"\u003eIdentify the signature of lambdas\u003c/a\u003e\u003cbr/\u003e\n   \u003ca href=\"#Settings---configure-replacements-and-indentation\"\u003eSettings - configure replacements and indentation\u003c/a\u003e\u003cbr/\u003e\n   \u003ca href=\"#Compile-time-constexpr-type-names\"\u003eCompile time constexpr type names\u003c/a\u003e\u003cbr/\u003e\n   \u003ca href=\"#Decipher-range-v3-auto-types\"\u003eDecipher range-v3 auto types\u003c/a\u003e\u003cbr/\u003e\n   \u003ca href=\"#Cheat-sheet\"\u003eCheat sheet\u003c/a\u003e\u003cbr/\u003e\n\n\u003c/p\u003e\n\u003c/tr\u003e\u003c/td\u003e\n\u003c/table\u003e\n\n\n\n\u003cimg src=\"https://raw.githubusercontent.com/pthom/cleantype/master/resources/cleantype_logo_small.jpg\" align=\"left\" width=\"200\"\u003e\n\u003ctable\u003e\n    \u003ctr\u003e        \n      \u003ctd\u003e\n        Travis \u003ca href=\"https://travis-ci.org/pthom/cleantype/\"\u003e \u003cimg src=\"https://travis-ci.org/pthom/cleantype.svg?branch=master\" /\u003e \u003c/a\u003e\n     \u003c/td\u003e\n     \u003ctd\u003e\n        Windows \u003ca href=\"https://ci.appveyor.com/project/pthom/cleantype\"\u003e \u003cimg src=\"https://ci.appveyor.com/api/projects/status/s6wmhg5q9l69w7aq/branch/master?svg=true\" /\u003e \u003c/a\u003e\n    \u003c/td\u003e\n     \u003ctd\u003e\n        License \u003ca href=\"https://www.boost.org/LICENSE_1_0.txt\"\u003e \u003cimg src=\"https://img.shields.io/badge/license-boost%201.0-blue.svg\" /\u003e \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n        Try this online!\n        \u003ca href=\"https://mybinder.org/v2/gh/pthom/cleantype/master?filepath=notebooks%2Fcleantype%2Fcleantype.ipynb\"\u003e \n            \u003cimg src=\"https://mybinder.org/badge_logo.svg\" /\u003e \n        \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n        Demo on gitpod\n        \u003ca href=\"https://gitpod.io/#https://github.com/pthom/cleantype/blob/master/demos/demo_simple.cpp\"\u003e \n            \u003cimg src=\"resources/gitpod.jpg\" width=\"50\" /\u003e \n        \u003c/a\u003e\n    \u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/table\u003e \n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n# CleanType: Readable C++ type introspection - Compiler Decipherer\n\n\n\nCleanType is a C++14 header only library which offer *readable* type names, with a *consistent naming scheme across compilers*, at *run-time* and *compile-time*. It can also output the *signature of lambda* functions, and the result type of any auto function.\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n## TLDR: a quick example for the impatient reader\n\n````cpp\n#include \u003ccleantype/cleantype.hpp\u003e\n#include \u003crange/v3/all.hpp\u003e\n\nint main() {\n  std::set\u003cstd::string\u003e v { \"Hello\", \"There\"};\n\n  // cleantype::full -\u003e full type string (the output will depend on the compiler and on the libc version)\n  std::cout \u003c\u003c cleantype::full(v) \u003c\u003c \"\\n\";\n  // =\u003e Outputs: std::set\u003cstd::__cxx11::basic_string\u003cchar\u003e, std::less\u003cstd::__cxx11::basic_string\u003cchar\u003e\u003e, std::allocator\u003cstd::__cxx11::basic_string\u003cchar\u003e\u003e\u003e \u0026\n\n  // cleantype::clean -\u003e readable type string (this string is constant across compilers and libc versions)\n  std::cout \u003c\u003c cleantype::clean(v) \u003c\u003c \"\\n\";\n  // Outputs: std::set\u003cstd::string\u003e \u0026\n\n  // cleantype::show_details -\u003e readable type string together with variable content\n  std::cout \u003c\u003c cleantype::show_details(v) \u003c\u003c \"\\n\";\n  // =\u003e Outputs: std::set\u003cstd::string\u003e \u0026 = [Hello, There]\n\n  // cleantype::clean -\u003e can automatically indent deeply nested types (this is optional)\n  using namespace ranges;\n  auto squares_take_10 =  view::for_each(view::ints(1), [](int x) { return ranges::yield(x * x); }) | view::take(10);\n  std::cout \u003c\u003c cleantype::clean(squares_take_10) \u003c\u003c \"\\n\";\n  // =\u003e Outputs:\n  // ranges::v3::detail::take_exactly_view_\u003c\n  //    ranges::v3::join_view\u003c\n  //        ranges::v3::transform_view\u003c\n  //            ranges::v3::iota_view\u003c\n  //                int,\n  //                void\n  //            \u003e,\n  //            (lambda at example.cpp:19:59)\n  //        \u003e,\n  //        void\n  //    \u003e,\n  //    false\n  //\u003e \u0026\n\n\n  // cleantype::lambda_clean -\u003e readable signature for lambda functions (generic and non generic lambdas)\n  auto add = [](auto a, auto b) { return a + b; };\n  std::cout \u003c\u003c cleantype::lambda_clean\u003cstd::string, char\u003e(add) \u003c\u003c \"\\n\";\n  // =\u003e Outputs: lambda: (std::string, char) -\u003e std::string\n}\n\n````\n\n\u003ca href=\"https://asciinema.org/a/HDu34hBlRJ8lbHPgvEXvvIqmN?speed=2.8\u0026t=14\" target=\"_blank\"\u003e\u003cimg src=\"https://asciinema.org/a/HDu34hBlRJ8lbHPgvEXvvIqmN.svg\" width=\"300\" align=\"right\" style=\"padding-left: 10px\"/\u003e\u003c/a\u003e\nThe video to the right gives a 2 minutes overview of the library. This demo uses [cling](https://root.cern.ch/cling), a fully compliant C++14 REPL, and [asciinema](https://asciinema.org/), a terminal session recorder. You can pause at any time, and copy-paste samples from it. Its source code is [here](demos/demo_cling.cpp).\n\n\nThe included tool `ct_compiler_decipher` simplifies the template noise in your compiler output: just ` \"|\" (pipe)` your build tool to it.\n\n\nCleantype can be seeen as a developper friendly `typeid` alternative, and as a tool for those who are tired by the template noise in the compiler output.\n\n\n\n\n#### Motivation\n\nIn C++, [typeid.name()](https://en.cppreference.com/w/cpp/language/typeid) is able to display the type of variables.\nHowever it has several limitations: `const`, `volatile`, `\u0026\u0026`qualifiers are ignored; it cannot identify the signature of lambdas function, and last but not least, the returned name if often unreadable: for example `std::set\u003cstd::string\u003e` becomes\n ````\n std::set\u003cstd::__cxx11::basic_string\u003cchar, std::char_traits\u003cchar\u003e, std::allocator\u003cchar\u003e \u003e, std::less\u003cstd::__cxx11::basic_string\u003cchar, std::char_traits\u003cchar\u003e, std::allocator\u003cchar\u003e \u003e \u003e, std::allocator\u003cstd::__cxx11::basic_string\u003cchar, std::char_traits\u003cchar\u003e, std::allocator\u003cchar\u003e \u003e \u003e \u003e\n ````\n\nThis library tries to overcomes some of these limitations. It is composed mainly of C++11 / C++14 functions. It also contains some macros in order to be able to display rvalue reference type, as well as variables names. Macros are prepended with a prefix 'CT_'.\n\nThe returned types names should be equal (or at least similar) accross compilers.\n\n#### Status\n\nNote: this library is heavily [tested](https://github.com/pthom/cleantype/tree/master/src/tests), with clang, gcc and msvc. However, it is subject to quick evolution, and should be considered as a beta version.\n\n#### More infos\nSee the [introductory blog post](http://code-ballads.net/cleantype/)\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n# Installation and usage\n\n\n* `cleantype`is a small header only library, so you just need to clone it and add it to your path. It works with C++ 14 and C++17; and is tested succesfully with gcc (\u003e=5), clang (\u003e=6), appleclang, and msvc (\u003e= MSVC 2017).\n\nThen, include [cleantype/cleantype.hpp](src/include/cleantype/cleantype.hpp) (this file includes a comprehensive API doc). Alternatively, you can use the \"all in one version\", which is comprised of [only one header file](include_all_in_one/include/cleantype/cleantype.hpp), inside the \"include_all_in_one\" folder.\n\n_Notes:_ \ncleantype can be used as a standalone library. However, in order to use be able to read settings from a preference file, you will need [nlohmann/json](https://github.com/nlohmann/json). If you want to use this feature, define `CLEANTYPE_USE_NLOHMANN_JSON` before including cleantype.hpp and make sure that nlohmann/json.hpp is in your include path.\n\n* `ct_compiler_decipher` is comprised of a single c++ file. It's compilation can be done via `make`\nor via `$(CXX) -Isrc/include -Ithird_party/FunctionalPlus/include --std=c++14 src/tools/ct_compiler_decipher/ct_compiler_decipher.cpp -o ct_compiler_decipher`\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n# About this manual\n\n\nThis manual is fully interactive! It was written using [cling](https://root.cern.ch/cling), [xeus cling](https://xeus-cling.readthedocs.io/en/latest/) and [jupyter notebook](https://jupyter.org/). Cling enables a Read-Eval-Print-Loop (REPL) development mode with C++. This approach benefits a lot from having a good type introspection, which is the aim of this library. I wrote an article which is a [\"hands-on session\"](http://code-ballads.net/read-eval-print-loop-repl-in-c/) about this for those who are interested.\n\nThe code that you read in this manual is real live code that can be executed inside jupyter notebook. \nYou can try it directly inside [binder](https://mybinder.org/): click on the \"launch binder\" at the top of this page.\u003cbr/\u003e\nNotes:\n* Beware, it may require about 1 minute to load; but then you will be able to run the code live from your browser!\n* Inside the notebook, click on the \"Run\" button in order to execute each cell (in order)\n* You can modify and run the code as you desire inside binder!\n* Note that there is a limitation in cling that *requires that you add two \";\" after each lambda function definition*\n\nThe \"#pragma cling add_include_path\" is specific to cling. Beside this, everything is standard C++.\n\n\n```c++\n// Special macro to change the include path (this is required for the binder demo)\n#pragma cling add_include_path(\"./include\")\n#include \u003ccleantype/cleantype.hpp\u003e\n\n// The includes below are not required, they are just used for the purpose of this manual\n#include \u003cfuture\u003e \n#include \u003cnumeric\u003e\n#include \u003cfplus/fplus.hpp\u003e\n```\n\n\n```c++\n// This macro is used later in this manual in order to display commands and their results\n#define run_show(...)                   \\\n{                                       \\\n    std::cout \u003c\u003c #__VA_ARGS__ \u003c\u003c \"\\n\";  \\\n    std::cout \u003c\u003c __VA_ARGS__ \u003c\u003c \"\\n\\n\"; \\\n}\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n# Readable type names and full type names\n\n\n ## Readable type names \n \n #### Functions operating on types and variables\n                \n* `cleantype::clean\u003cT...\u003e()` is a function that will return a string containing\n   a readable type, for a given type or pack of types.\n   Use it with \"cleantype::clean\u003cdecltype(var)\u003e()\"\u003cbr/\u003e\n   Note: It will add a reference by default so that \"int v = 5; cleantype::clean(v)\" will return \"int\u0026\". \n   Use the macro CT_cleantype_clean() if you want to avoid this\n\n* `cleantype::clean\u003cT...\u003e(t...)` is a an easier version, using an instance of the type.\u003cbr/\u003e\n    Notes:\n     * It will add a reference. Use the macro CT_cleantype_clean() if you want to avoid this\n     * It is not able to output correctly r-value references. For this, use `cleantype::clean\u003cdecltype(var)\u003e()`\n\n* `cleantype::show_details(T \u0026\u0026 v)` is a function that will return a string containing\n   the readable type of a variable, as well as its content\n\n* `CT_cleantype_clean(var)` is a macro that will also return the full type,\n   but, it is able to also correctly display rvalue reference types.\n\n*  `CT_show_details(var)` is a macro that will return a string containing the name,\n   type and content of a variable (in this case, the underlying type of 'var'\n   has to have an 'ostream \u0026 operator\u003c\u003c')\n\n* `CT_show_details_cont` (macro) is a version of CT_show_details for complex containers\n   like \"std::map\". \"cont\" stands for \"container\".\n   \n#### Functions operating on strings\n\n* `cleantype::clean_typestring(type_names)` will clean a given (list of) type(s) given as a string\n* `cleantype::indent_type_tree(type_names)` will present an indented view of a given (list of) type(s).\n\n_Note_: by default, types will be presented with an indentation as soon as the type tree depth is \u003e 3. \n\n\n### Examples\n\n\n```c++\n// Lets define a function with an auto return type: what is its return type?\nauto my_range(int nb)\n{\n    std::list\u003cint\u003e l(nb);\n    std::iota(l.begin(), l.end(), 1);\n    return l;\n}\nauto v = my_range(5);\n```\n\n\n```c++\nrun_show(     cleantype::clean(v)                   )\nrun_show(     cleantype::clean\u003cdecltype(v)\u003e()       )\nrun_show(     cleantype::show_details(v)            )\nrun_show(     CT_cleantype_clean(v)                 )\nrun_show(     CT_show_details(v)                    )\n```\n\n    cleantype::clean(v)\n    std::list\u003cint\u003e \u0026\n    \n    cleantype::clean\u003cdecltype(v)\u003e()\n    std::list\u003cint\u003e\n    \n    cleantype::show_details(v)\n    std::list\u003cint\u003e \u0026 = [1, 2, 3, 4, 5]\n    \n    CT_cleantype_clean(v)\n    std::list\u003cint\u003e\n    \n    CT_show_details(v)\n    [std::list\u003cint\u003e] v = [1, 2, 3, 4, 5]\n    \n\n\n### Example with rvalue references\nBelow, an where a function receives value by r-value references and can display its type \u0026 value correctly.\n\n\n```c++\n{\n    auto log_received = [](auto \u0026\u0026 v) {\n        std::cout \u003c\u003c cleantype::full\u003cdecltype(v)\u003e() \u003c\u003c std::endl;\n        std::cout \u003c\u003c CT_show_details(v) \u003c\u003c \"\\n\";\n    };\n    log_received(42);\n}\n```\n\n    int \u0026\u0026\n    [int \u0026\u0026] v = 42\n\n\n### Examples with arguments pack\n\n\n```c++\nstd::cout \u003c\u003c cleantype::clean(1, \"Hello\") \u003c\u003c std::endl;\nstd::cout \u003c\u003c cleantype::clean\u003cstd::string, int, int \u0026\u0026, char \u0026\u0026\u003e() \u003c\u003c std::endl;\n```\n\n    int, char const(\u0026) [6] \n    std::string, int, int \u0026\u0026, char \u0026\u0026\n\n\n### Example with strings\n\n\n```c++\n{\n    // clean_typestring\n    run_show(  cleantype::clean_typestring(\"std::__cxx11::list\u003cint, std::allocator\u003cint\u003e \u003e\")    );\n\n    // indent_type_tree\n    run_show(  cleantype::indent_type_tree(\"std::deque\u003cstd::pair\u003cstd::string, std::map\u003cint, int\u003e\u003e\u003e\")    );\n}\n```\n\n    cleantype::clean_typestring(\"std::__cxx11::list\u003cint, std::allocator\u003cint\u003e \u003e\")\n    std::list\u003cint\u003e\n    \n    cleantype::indent_type_tree(\"std::deque\u003cstd::pair\u003cstd::string, std::map\u003cint, int\u003e\u003e\u003e\")\n    std::deque\u003c\n        std::pair\u003c\n            std::string,\n            std::map\u003c\n                int,\n                int\n            \u003e\n        \u003e\n    \u003e\n    \n\n\n### Configuration of the clean types\n\nYou can customize the suppressions and replacements inside [cleantype/cleantype_configuration.hpp](src/include/cleantype/cleantype_configuration.hpp)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n## Full type names\n\n* `cleantype::full\u003cT...\u003e()` is a function that will return a string containing\n   the full type. It also works with packs of types. Use it with \"cleantype::full\u003cdecltype(var)\u003e()\"\u003cbr/\u003e\n   It will add a reference by default so that \"int v = 5; cleantype::full(v)\" will return \"int\u0026\". \n   Use the macro CT_cleantype_full() if you want to avoid this\n\n* `cleantype::full\u003cT...\u003e(t...)` is a an easier version, using an instance of the type.\u003cbr/\u003e\n   Notes:\n     * It will add a reference by default so that\n        int v = 5; cleantype::full(v) will return \"int\u0026\"\n        =\u003e use the macro CT_cleantype_full() if you want to avoid this\n     * It is not able to output correctly r-value references\n         For this, use `cleantype::full\u003cdecltype(var)\u003e()`\n\n* `cleantype::show_details_full(T \u0026\u0026 v)` is a function that will return a string containing\n   the full type of a variable, as well as its content\n\n* `CT_cleantype_full(var)` is a macro that will also return the full type,\n   but, it is able to also correctly display rvalue reference types.\n\n*  `CT_show_details_full(var)` is a macro that will return a string containing the name,\n   type and content of a variable (in this case, the underlying type of 'var'\n   has to have an 'ostream \u0026 operator\u003c\u003c')\n\n* `CT_show_details_full_cont` is a version of CT_show_details_full for complex containers\n   like \"std::map\". \"cont\" stands for \"container\".\n\n\n\n\n```c++\n{\n    auto w = my_range(10);\n    run_show(     cleantype::full(w)                         )\n    run_show(     cleantype::full\u003cdecltype(w)\u003e()             )\n    run_show(     cleantype::show_details_full(w)            )\n    run_show(     CT_cleantype_full(w)                       )\n    run_show(     CT_show_details_full(w)                    )\n}\n```\n\n    cleantype::full(w)\n    std::__cxx11::list\u003cint, std::allocator\u003cint\u003e\u003e \u0026\n    \n    cleantype::full\u003cdecltype(w)\u003e()\n    std::__cxx11::list\u003cint, std::allocator\u003cint\u003e\u003e\n    \n    cleantype::show_details_full(w)\n    [std::__cxx11::list\u003cint, std::allocator\u003cint\u003e\u003e \u0026] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n    \n    CT_cleantype_full(w)\n    std::__cxx11::list\u003cint, std::allocator\u003cint\u003e\u003e\n    \n    CT_show_details_full(w)\n    [std::__cxx11::list\u003cint, std::allocator\u003cint\u003e\u003e] w = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n    \n\n\n### Full type versus readable type:\nFull types can quickly become unreadable, especially with templated types, such as in the STL.\n\n\n```c++\n{\n    std::set\u003cstd::string\u003e my_set { \"Hello\", \"There\"};\n    run_show(     cleantype::show_details_full(my_set)               )\n    run_show(     cleantype::show_details(my_set)                    )\n}\n```\n\n    cleantype::show_details_full(my_set)\n    [std::set\u003cstd::__cxx11::basic_string\u003cchar, std::char_traits\u003cchar\u003e, std::allocator\u003cchar\u003e\u003e, std::less\u003cstd::__cxx11::basic_string\u003cchar, std::char_traits\u003cchar\u003e, std::allocator\u003cchar\u003e\u003e\u003e, std::allocator\u003cstd::__cxx11::basic_string\u003cchar, std::char_traits\u003cchar\u003e, std::allocator\u003cchar\u003e\u003e\u003e\u003e \u0026] = [Hello, There]\n    \n    cleantype::show_details(my_set)\n    std::set\u003cstd::string\u003e \u0026 = [Hello, There]\n    \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n## Display the content of complex containers\n\n\n* `CT_show_details_cont` (macro) is a version of CT_show_details for complex containers\n   like \"std::map\". \"cont\" stands for \"container\".\n* `CT_show_details_full_cont` enables to display the full type and content\n\nThese version are required for certains more complex containers, like \"std::map\". \"cont\" stands for \"container\".\n\n\n```c++\n{\n    std::map\u003cstd::string, int\u003e my_map {{{\"a\", 1}, {\"b\", 2}, {\"c\", 3} }};\n    run_show(     CT_show_details_cont(my_map)                    )\n    run_show(     CT_show_details_full_cont(my_map)               )\n}\n```\n\n    CT_show_details_cont(my_map)\n    [std::map\u003cstd::string, int\u003e] my_map = [(a, 1), (b, 2), (c, 3)]\n    \n    CT_show_details_full_cont(my_map)\n    [std::map\u003cstd::__cxx11::basic_string\u003cchar, std::char_traits\u003cchar\u003e, std::allocator\u003cchar\u003e\u003e, int, std::less\u003cstd::__cxx11::basic_string\u003cchar, std::char_traits\u003cchar\u003e, std::allocator\u003cchar\u003e\u003e\u003e, std::allocator\u003cstd::pair\u003cconst std::__cxx11::basic_string\u003cchar, std::char_traits\u003cchar\u003e, std::allocator\u003cchar\u003e\u003e, int\u003e\u003e\u003e] my_map = [(a, 1), (b, 2), (c, 3)]\n    \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n# Decipher compiler output and identify types in the compiler output\n\n\u003ca href=\"https://asciinema.org/a/227653?speed=8\" target=\"_blank\"\u003e\u003cimg src=\"https://asciinema.org/a/227653.svg\" width=\"200\" align=\"right\" style=\"padding-left: 20px\"/\u003e\u003c/a\u003e\n* `ct_compiler_decipher` is a tool that deciphers the compiler output and makes it more readable, especially when there are lots of templates\n* `CT_compiler_log_type(T)` is a macro that will create an intentional compiler error whose intent is to display the type name of T. You can use it in conjunction with \"ct_compiler_decipher\".\n* `CT_compiler_log_var_type` is a macro that will create an intentional compiler error whose intent is to display the type name of the variable var. You can use it in conjunction with \"ct_compiler_decipher\".\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n## Decipher the compiler output\n\n\n#### Build `ct_compiler_decipher`\nFirst let's build ct_compiler_decipher: it is composed of unique cpp file, so that it's compilation is extremely easy\n\n\n```c++\n#include \"build_ct_tools.cpp\"\nmake_ct_compiler_decipher();\n```\n\n    make 2\u003e\u00261\n    g++ -Isrc/include --std=c++14 src/tools/ct_compiler_decipher/ct_compiler_decipher.cpp -o ct_compiler_decipher\n\n\n#### Sample code with an error for which we want to deciher the compiler output\nThe code below is intentionally bad, in order to get the compiler to spit incomprehensible template errors. Do not even try to make sense out of it :-)\n\n\n```c++\nstd::string code =\nR\"CODE(\n #include \u003cfplus/fplus.hpp\u003e\n #include \u003cstring\u003e\n #include \u003cmap\u003e\n #include \u003cvector\u003e\n\nauto buggy_lambda = [](int a, int b) {\n    std::map\u003cstd::string, int\u003e r1;\n    std::vector\u003cdecltype(r1)\u003e r2;\n    for (std::size_t i = 0; i \u003c b; i++) r2.push_back(r1);\n    auto add_one = [](auto x) { return x + 1; };\n    auto r3 = fplus::transform(add_one, r2);\n    return r3;\n};\n\nint main() { auto v = buggy_lambda(1, 3); }\n\n)CODE\";\n```\n\n#### Compile and decipher\nLet's compile it with the default compiler. Below, we only show the begining of the compiler output (it is followed by around 90 similar lines).\n\n\n```c++\ncompile_code__extract(code);\n```\n\n    clang++ --std=c++14 -c code.cpp -Iinclude -o a.out 2\u003e\u00261 | head -5 2\u003e\u00261\n    code.cpp:10:42: error: invalid operands to binary expression ('std::map\u003cstd::__cxx11::basic_string\u003cchar\u003e, int, std::less\u003cstd::__cxx11::basic_string\u003cchar\u003e \u003e, std::allocator\u003cstd::pair\u003cconst std::__cxx11::basic_string\u003cchar\u003e, int\u003e \u003e \u003e' and 'int')\n        auto add_one = [](auto x) { return x + 1; };\n                                           ~ ^ ~\n    include/fplus/internal/invoke.hpp:211:26: note: in instantiation of function template specialization '(anonymous class)::operator()(int, int)::(anonymous class)::operator()\u003cstd::map\u003cstd::__cxx11::basic_string\u003cchar\u003e, int, std::less\u003cstd::__cxx11::basic_string\u003cchar\u003e \u003e, std::allocator\u003cstd::pair\u003cconst std::__cxx11::basic_string\u003cchar\u003e, int\u003e \u003e \u003e \u003e' requested here\n        FPLUS_INVOKE_RETURN((std::forward\u003cF\u003e(f)(std::forward\u003cArgs\u003e(args)...)))\n\n\nLet's commpile it and pipe the compiler output to `ct_compiler_decipher`:\n```bash\nclang++ --std=c++14 -c code.cpp -Iinclude -o a.out 2\u003e\u00261 | ct_compiler_decipher\n```\n\n\n```c++\ncompile_code_decipher__extract(code);\n```\n\n    clang++ --std=c++14 -c code.cpp -Iinclude -o a.out 2\u003e\u00261 | ct_compiler_decipher | head -5 2\u003e\u00261\n    code.cpp:10:42: error: invalid operands to binary expression('std::map\u003cstd::string, int\u003e ' and 'int')\n        auto add_one = [](auto x) { return x + 1; };\n                                           ~ ^ ~\n    include/fplus/internal/invoke.hpp:211:26: note: in instantiation of function template specialization '(anonymous class)::operator()(int, int)::(anonymous class)::operator()\u003cstd::map\u003cstd::string, int\u003e\u003e ' requested here\n    FPLUS_INVOKE_RETURN((std::forward\u003cF, Args\u003e(f)(std::forward(args)...)))\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n## Identify types names at compile time, with clean names\n\n\nSometimes it is easier to be able to identify a type at compile time. This is especially true, if the code in question is run long after the application start.\n\nIn this case, the macros `CT_compiler_log_type(T)` and `CT_compiler_log_var_type` come handy. They  will create an intentional compiler error whose intent is to display the type name of the variable var. You can use them in conjunction with \"ct_compiler_decipher\".\n\nSee an example below:\n\n\n```c++\nstd::string code2 =\nR\"CODE(\n #include \u003ccleantype/cleantype.hpp\u003e\n #include \u003cfplus/fplus.hpp\u003e\n \n auto mystery_lambda = [](int end) {    \n    return fplus::overlapping_pairs_cyclic( fplus::numbers(0, end) );\n };\n int main() {\n    auto v = mystery_lambda(10);\n    CT_compiler_log_var_type(v); // Here we ask the compiler to give us the type of v\n }\n)CODE\";\n```\n\n\n```c++\ncompile_code_decipher__extract(code2);\n```\n\n    clang++ --std=c++14 -c code.cpp -Iinclude -o a.out 2\u003e\u00261 | ct_compiler_decipher | head -5 2\u003e\u00261\n    code.cpp:10:5: error: no member named 'IntentionalError' in 'std::vector\u003cstd::pair\u003cint, int\u003e\u003e '\n        CT_compiler_log_var_type(v); // Here we ask the compiler to give us the type of v\n        ^                        ~\n    include/cleantype/details/cleantype_full.hpp:103:13: note: expanded from macro 'CT_compiler_log_var_type'\n            var.IntentionalError = 42;    \\\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n# Identify the auto return type of functions and functors\n\n\n* `cleantype::invoke_result\u003cF, Args...\u003e::type` and `cleantype::invoke_result_t\u003cF, Args...\u003e` will contain the type of any function / lambda / functor. This is a __type__, _not a string_. \n* `CT_invoke_result_fn(F, Args...)` and `CT_invoke_result_fn_template(F, Args...)` are macros that makes it easy to get the return _type_ of a function whose return type is marked as \"auto\" (the second version is for template functions)\n* `CT_type_fn`, `CT_type_fn_template`, `CT_type_fn_full` and `CT_type_fn_template_full` are macros that return a _string_ containing the return type of a function whose return type is marked as \"auto\"\n\n__Notes:__\n* \"cleantype::invoke_result_t\" is a C++14 polyfill for [`std::invoke_result`](https://en.cppreference.com/w/cpp/types/result_of) (C++14 only provides \"std::result_of\", which is to be deprecated soon). When using C++17, it uses std::invoke_result in the background.\n* Yes, \"CT_invoke_result_fn\" is indeed a variadic macro!\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n## Examples\n\n\n### Using invoke_result and invoke_result_t: get the return type as a type\n\n\n```c++\nnamespace {\n    auto add_auto_fn(int a, int b) { return a + b; }\n    template\u003ctypename U, typename V\u003e auto add_auto_template_fn(U a, V b) { return a + b; }\n    struct my_functor{ auto operator() (int a) { return a + 42; }  };\n}\nvoid static_test_invoke_result()\n{\n    // For auto functions: use cleantype::invoke_result_t\u003c decltype(\u0026f), Args... \u003e\n    using T = cleantype::invoke_result_t\u003c decltype(\u0026add_auto_template_fn\u003cint, double\u003e), int, double\u003e;\n    static_assert(std::is_same\u003cT, double\u003e::value, \"\");\n\n    // For templated auto functions: use cleantype::invoke_result_t\u003c decltype(\u0026f\u003cArgs...\u003e), Args... \u003e\n    using U = cleantype::invoke_result_t\u003c decltype(\u0026add_auto_template_fn\u003cint, double\u003e), int, double\u003e;\n    static_assert(std::is_same\u003cU, double\u003e::value, \"\");\n\n    // For generic lambdas: use cleantype::invoke_result_t\u003c decltype(lambda), Args... \u003e\n    auto generic_lambda = [](auto a) {  return a + 42; };\n    using V = cleantype::invoke_result_t\u003c decltype(generic_lambda), double\u003e;\n    static_assert(std::is_same\u003cV, double\u003e::value, \"\");\n\n    // For functors: use cleantype::invoke_result_t\u003c functor, Args... \u003e\n    using W = cleantype::invoke_result_t\u003c my_functor, int\u003e;\n    static_assert(std::is_same\u003cW, int\u003e::value, \"\");\n}\n\n```\n\n### Get the return type as a string with `CT_type_fn`\n\n\n```c++\n// For auto functions: display their return type with CT_type_fn(f, Args...)\nrun_show (       CT_type_fn(add_auto_fn, int, int)                                   );\n\n// For templated auto functions: display their return type with CT_type_fn_template(f, Args...)\nrun_show (       CT_type_fn_template(add_auto_template_fn, std::string, char)        );\n```\n\n    CT_type_fn(add_auto_fn, int, int)\n    int\n    \n    CT_type_fn_template(add_auto_template_fn, std::string, char)\n    std::string\n    \n\n\n__Limitations of invoke_result with MSVC 2017 and templated auto functions__:\n\n`invoke_result` does not work under MSVC with template functions whose return type is auto (see https://stackoverflow.com/questions/54111146/invoke-result-for-template-function-with-auto-return-type-and-msvc-2017)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n# Identify the signature of lambdas\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n## Non generic lambdas\n\n* `cleantype::lambda\u003ctypename... Args, typename Lambda\u003e(Lambda fn, bool flag_clean)` is a function that will return\n    a string containing the signature of a lambda. flag_clean controls wether the signature is cleaned or not.\n\n* `cleantype::lambda_clean\u003ctypename... Args, typename Lambda\u003e(Lambda fn)` is a function that will return a string containing the readable signature of a lambda.\n\n* `cleantype::lambda_full\u003ctypename... Args, typename Lambda\u003e(Lambda fn)` is a function that will return a string containing the full signature of a lambda\n\n*  `CT_show_details_lambda(var)` is a macro that will return a string containing the\n   readable signature of a lambda and its name\n\n*  `CT_show_details_lambda_full(var)` is a macro that will return a string containing the\n   full signature of a lambda and its name\n\nIt is not alway easy to guess the return type of lambda. See the lambda below for example. \n\u003cbr/\u003eIts return type is not easy to guess:\n\n\n```c++\nint start = 5;\n// what is the return type of this lambda?\nauto mystery_lambda = [\u0026start](int end) {    \n    return fplus::overlapping_pairs_cyclic( fplus::numbers(start, end) );\n};;\n```\n\n\n```c++\n// Let's see\nrun_show(            cleantype::lambda_clean(mystery_lambda)          );\nrun_show(            CT_show_details_lambda(mystery_lambda)           );\n```\n\n    cleantype::lambda_clean(mystery_lambda)\n    lambda: (int) -\u003e std::vector\u003cstd::pair\u003cint, int\u003e\u003e\n    \n    CT_show_details_lambda(mystery_lambda)\n    [lambda: (int) -\u003e std::vector\u003cstd::pair\u003cint, int\u003e\u003e] mystery_lambda\n    \n\n\n\n#### Note\nIf we try to get the type of this lambda via `cleantype::full`, we do not get much information...\n\n\n```c++\nstd::cout \u003c\u003c cleantype::full\u003cdecltype(mystery_lambda)\u003e();\n```\n\n    (lambda at input_line_29:4:23)\n\nThis is because \"mystery_lambda\" is actually a instance of a hidden class. We are actually looking for the signature of the operator() of this class. `type_lambda_clean` is able to extract the type of this operator and to display it in a readable way.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n## Generic lambdas\n\n\n* `cleantype::lambda`, `cleantype::lambda_clean` and `cleantype::lambda_full` are compatible with generic lambdas, provided that you specify the type of the \"auto\" params during the call.\n*  `CT_type_lambda_generic_fromparams_XXX(lambda, arg1, arg2, ...)` is a macro that will return a string containing the signature of a generic lambda where you do not specify the args type, instead you give example of these types.\n    (XXX is the number of params of the lambda, and can vary from 1 to 5).\n\nNote: getting the signature of generic lambdas is an advanced feature, and it might fail on certain compilers, such as gcc (in which case, you will get no output).\n\n### Example\n\n\n```c++\nauto add = [](auto a, auto b) {\n    return a + b; \n};;\n```\n\nThis lambda (\"add\") is a generic lambda (which means that at least one of its argument is specified with an \"auto\" type). It's behaviour is comparable to a template function.\n\nSo, if we try to get its signature via a direct call to `cleantype::lambda_clean` like below:\n\n```cpp\nstd::cout \u003c\u003c cleantype::lambda_clean(add) \u003c\u003c std::endl;\n```\nThe compiler will complain:\n```\ncleantype/details/cleantype_lambda.hpp:29:18: error: variable 'as_ptr' with type 'auto' has incompatible initializer of type '\u003coverloaded function type\u003e'\n   auto as_ptr = \u0026Lambda::operator(); // if you have an error here, your lambda is generic! Add template params for its input types!\n```\n\nThe solution is to provide the types of the input parameters, like below:\n\n\n```c++\n// extract the lambda type using actual types\nstd::cout \u003c\u003c cleantype::lambda_clean\u003cint, double\u003e(add) \u003c\u003c std::endl;\n```\n\n    lambda: (int, double) -\u003e double\n\n\nIt can also be done by providing some example parameters: use `CT_type_lambda_generic_fromparams_XXX`, where X is the number of parameters of the lambda.\n\n\n```c++\n// extract the lambda type using example params\nstd::cout \u003c\u003c CT_type_lambda_generic_fromparams_2(add, 1u, -2);\n```\n\n    lambda: (unsigned int, int) -\u003e unsigned int\n\nThis second version is useful when you are lost in a forest of \"auto\" variables deep in the call stack, and you do not know the return type of the lambda, and you do not even know the type of the input parameters: in that case, if you have a working call example, then you can use it.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n# Settings - configure replacements and indentation\n\n\nIn order to configure the behavior of cleantype:\n\n* Duplicate the file `.cleantype.json` at the root of the cleantype repository, and place it wherever in the hierarchy of the parent directories of your application. \n\u003cbr/\u003e_Note_: you can also edit the example json file via [an interactive online editor](https://jsoneditoronline.org/?id=df38aa61554e4aad92883eaede62edc2)\n* Edit this file as a normal json file\n* Save this file in anywhere in the hierarchy of the parent directories of the execution directory.\n\nThe content of the pref file is self explanatory:\n\n````json\n{\n    \"force_east_const_\": false,\n    \"indent_depth_limit\": 3,\n    \"replacements_after_undesirable_node_extractions\": {\n        \"basic_string\u003c_CharT, _Traits, _Allocator\u003e\": \"std::string\",\n        \"std::basic_string\u003cchar\u003e\": \"std::string\"\n    },\n    \"suppress_custom_\": [\n        \" __ptr64\"\n    ],\n    \"suppress_extra_namespaces_\": [\n        \"::__1\",\n        \"::__cxx11\"\n    ],\n    \"suppress_extract_struct_class_\": [\n        \"class \",\n        \"struct \"\n    ],\n    \"undesirable_type_nodes_\": [\n        \"std::char_traits\",\n        \"std::allocator\",\n        \"std::less\"\n    ]\n}\n\n````\n\n_Note:_ \n* the library [nlohmann/json](https://github.com/nlohmann/json) is required in order to read/save the prefs from a json file. \n* in order to use the settings feature, define `CLEANTYPE_USE_NLOHMANN_JSON` before including cleantype.hpp and make sure that `nlohmann/json.hpp` is in your include path (you can find a version of it at `third_party/nlohmann_json/nlohmann/json.hpp`)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n# Compile time constexpr type names\n\n\n### Get the typename as a Boost.Hana string\n\n* `cleantype::full_compiletime\u003cT\u003e()` will give you the full name of a type in the form of a Boost.Hana string.\n\n**Note:** For this, you need to manually include \"cleantype/cleantype_compiler_typename.hpp\", and to have boost in your include path. The rest of the library (including ct_compiler_decipherer) can be compiled in a standalone way.\n\n\n### Note about constexpr type names:\n\nThe basic idea of having compile time type name is to use `__PRETTY_FUNCTION__` as a way to get the type name in a constexpr way. The original idea comes from the [ctti library](https://github.com/Manu343726/ctti), and is also used inside Boost.Hana's [experimental/type_name.hpp](https://github.com/boostorg/hana/blob/master/include/boost/hana/experimental/type_name.hpp). \n\nThis project goes beyond what was done in these projects, by adding a support for gcc and msvc (only clang was supported originaly).\n\nBased on the work done during the development of this librayr, a [Pull Request](https://github.com/boostorg/hana/pull/432) was posted to Boost.Hana. It proposes to include the support of MSVC and GCC for boost/hana/experimental/type_name.hpp.\n\n\n### Example\n\n\n```c++\n#include \u003ccleantype/cleantype_compiler_typename.hpp\u003e\n{\n    auto hana_type_string = cleantype::full_compiletime\u003cstd::pair\u003cint, char\u003e\u003e();\n    run_show(      cleantype::full(hana_type_string)      );\n}\n```\n\n    cleantype::full(hana_type_string)\n    boost::hana::string\u003c's', 't', 'd', ':', ':', 'p', 'a', 'i', 'r', '\u003c', 'i', 'n', 't', ', ', ' ', 'c', 'h', 'a', 'r', '\u003e'\u003e \u0026\n    \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n# Decipher range-v3 auto types\n\n\n[range-v3](https://github.com/ericniebler/range-v3) is a library which contains the current state of the ranges proposal that will be included in C++ 20.\nIt allows very expressive code. However, the design of the library is based on a complex collection of types, so that most of the functions and variables can only be noted as `auto`.  \n\n`cleantype` can help in deciphering what's going on with the types with range-v3: \n\nFirst, we include cleantype and the range-v3 library\n\n_Note: the examples with ranges-v3 do not work currently in the interactive version on binder (due to a default in the compiler input path). Please install cleantype locally in order to tests them._\n\n\n```c++\n#pragma cling add_include_path(\"./include\")\n#include \u003ccleantype/cleantype.hpp\u003e\n#include \u003crange/v3/all.hpp\u003e\n\n#define run__show(...)                  \\\n{                                       \\\n    std::cout \u003c\u003c #__VA_ARGS__ \u003c\u003c \"\\n\";  \\\n    std::cout \u003c\u003c __VA_ARGS__ \u003c\u003c \"\\n\\n\"; \\\n}\nusing namespace ranges;\n```\n\nThen we set the indent depth limit to 2, because indenting will make the types much easier to read, since `range-v3` uses long and deep nested types. \n\n\n```c++\ncleantype::CleanConfiguration::GlobalConfig().indent_depth_limit = 2;\n```\n\n### Example of a view that return square numbers\n\nLet's define a function that yields using `ranges::yield` and, then let's identify its return type.\n\n\n```c++\nauto square_yield_fn(int x) {\n    return ranges::yield(x * x);\n}\nrun__show(  CT_type_fn(square_yield_fn, int)  );\n```\n\n    CT_type_fn(square_yield_fn, int)\n    ranges::v3::single_view\u003cint\u003e\n    \n\n\nNow, let's define a view that transform ints into squares. This view is lazy, and unlimited (it never ends). We then identify its type:\n\n\n```c++\nauto squares_view_fn = view::for_each(view::ints(1), square_yield_fn);\nrun__show(  cleantype::clean(squares_view_fn)  );\n```\n\n    cleantype::clean(squares_view_fn)\n    ranges::v3::join_view\u003c\n        ranges::v3::transform_view\u003c\n            ranges::v3::iota_view\u003c\n                int,\n                void\n            \u003e,\n            ranges::v3::single_view\u003c\n                int\n            \u003e (*)(int)\n        \u003e,\n        void\n    \u003e \u0026\n    \n\n\n\n```c++\nauto squares_fn_take_10 = squares_view_fn | view::take(10);\nrun__show(  cleantype::clean(squares_fn_take_10)  );\n```\n\n    cleantype::clean(squares_fn_take_10)\n    ranges::v3::detail::take_exactly_view_\u003c\n        ranges::v3::join_view\u003c\n            ranges::v3::transform_view\u003c\n                ranges::v3::iota_view\u003c\n                    int,\n                    void\n                \u003e,\n                ranges::v3::single_view\u003c\n                    int\n                \u003e (*)(int)\n            \u003e,\n            void\n        \u003e,\n        false\n    \u003e \u0026\n    \n\n\n### Example with range-v3 and lambdas:\n\nSince lambda are actually anonymous structs, cleantype cannot disclose the signature of the inner lambda of a view that is contructed using a lambda. \n\n\n```c++\n{\n    using namespace ranges;\n    \n    auto square_yield_lambda = [](int x) {\n        return yield(x * x);\n    };\n    run__show(  cleantype::lambda_clean(square_yield_lambda)  );\n    auto squares_view_lambda = view::for_each(view::ints(1), square_yield_lambda);\n    run__show(  cleantype::clean(squares_view_lambda)  );\n}\n```\n\n    cleantype::lambda_clean(square_yield_lambda)\n    lambda: (int) -\u003e ranges::v3::single_view\u003cint\u003e\n    \n    cleantype::clean(squares_view_lambda)\n    ranges::v3::join_view\u003c\n        ranges::v3::transform_view\u003c\n            ranges::v3::iota_view\u003c\n                int,\n                void\n            \u003e,\n            (lambda at input_line_44:5:32)\n        \u003e,\n        void\n    \u003e \u0026\n    \n\n\nIn an ideal world, I would be interesting to be able to display the view type as below (but I'm afraid that the code in order to get to this might be intractable).\n\n````\nranges::v3::join_view\u003c\n    ranges::v3::transform_view\u003c\n        ranges::v3::iota_view\u003c\n            int,\n            void\n        \u003e,\n        lambda: (int) -\u003e ranges::v3::single_view\u003cint\u003e\n    \u003e,\n    void\n\u003e \u0026\n````\n\nThus, it is advised to prefer \"auto return functions\" to lambdas when using range-v3 with cleantype.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\u003ca href=\"#Table-of-content\"\u003e\u003cimg src=\"https://img.shields.io/badge/%3C%20top-E7E7E7.svg\" align=\"right\"\u003e\u003c/a\u003e\n# Cheat sheet\n\n[cleantype.hpp](https://github.com/pthom/cleantype/blob/master/src/include/cleantype/cleantype.hpp) offers a quick cheat sheet to all the functions and macros available.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpthom%2Fcleantype","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpthom%2Fcleantype","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpthom%2Fcleantype/lists"}