diff --git a/README.md b/README.md index db3942d..167287e 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,51 @@ -# mp11, a simple C++11 metaprogramming library +# Mp11, a C++11 metaprogramming library -For background, please see the article ["Simple C++11 metaprogramming"](http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html). +Mp11 is a C++11 metaprogramming library based on template aliases and variadic templates. +It implements the approach outlined in the article +["Simple C++11 metaprogramming"](http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html) +and [its sequel](http://pdimov.com/cpp2/simple_cxx11_metaprogramming_2.html). Reading these +articles before proceeding with the documentation is _highly_ recommended. -The library should be placed in a subdirectory `libs/mp11` in a Boost distribution. There is [documentation](https://rawgit.com/pdimov/mp11/master/doc/html/mp11.html) in `doc/html/mp11.html`. +The library is intended to be placed in a subdirectory `libs/mp11` in a Boost distribution, +but can also be used standalone, although it does require Boost.Config. A single-header form +is available in [include/boost/mp11_single.hpp](include/boost/mp11_single.hpp). -Supported compilers: +## Supported compilers * g++ 4.7 or later * clang 3.5 or later * Visual Studio 2013, 2015, 2017 + +## Documentation + +[Overview](doc/mp11/overview.adoc) + +[Definitions](doc/mp11/definitions.adoc) + +[Examples](doc/mp11/examples.adoc) + +[Reference](doc/mp11/reference.adoc) + +* [Integral Constants](doc/mp11/integral.adoc) + +* [List Operations](doc/mp11/list.adoc) + +* [Utility Components](doc/mp11/utility.adoc) + +* [Algorithms](doc/mp11/algorithm.adoc) + +* [Set Operations](doc/mp11/set.adoc) + +* [Map Operations](doc/mp11/map.adoc) + +* [Helper Metafunctions](doc/mp11/function.adoc) + +* [Bind](doc/mp11/bind.adoc) + +* [Integer Sequences](doc/mp11/integer_sequence.adoc) + +* [A "for each" algorithm for tuple-like types](doc/mp11/tuple_for_each.adoc) + +## License + +Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt). diff --git a/doc/Jamfile b/doc/Jamfile new file mode 100644 index 0000000..727d6c8 --- /dev/null +++ b/doc/Jamfile @@ -0,0 +1,26 @@ +# Copyright 2017 Peter Dimov +# +# Distributed under the Boost Software License, Version 1.0. +# +# See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt + +project doc/mp11 ; + +import asciidoctor ; + +html mp11.html : mp11.adoc ; + +install html_ : mp11.html : html ; + +pdf mp11.pdf : mp11.adoc ; +explicit mp11.pdf ; + +install pdf_ : mp11.pdf : pdf ; +explicit pdf_ ; + +############################################################################### +alias boostdoc ; +explicit boostdoc ; +alias boostrelease ; +explicit boostrelease ; diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 deleted file mode 100644 index 6274279..0000000 --- a/doc/Jamfile.v2 +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2002 Douglas Gregor -# Copyright 2017 Peter Dimov - -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -project doc/mp11 ; - -import boostbook ; -import quickbook ; - -xml mp11_ : mp11.qbk : on ; -boostbook standalone_mp11 - : - mp11_ - : - boost.root=../../../.. - # File name of HTML output: - root.filename=mp11 - # How far down we chunk nested sections, basically all of them: - chunk.section.depth=0 - # Don't put the first section on the same page as the TOC: - chunk.first.sections=0 - # How far down sections get TOC's - toc.section.depth=3 - # Max depth in each TOC: - toc.max.depth=3 - # How far down we go with TOC's - generate.section.toc.level=0 - - generate.manifest=0 - - html.stylesheet=../css/boostbook.css - ; - -############################################################################### -alias boostdoc ; -explicit boostdoc ; -alias boostrelease : standalone_mp11 ; -explicit boostrelease ; diff --git a/doc/asciidoctor.jam b/doc/asciidoctor.jam new file mode 100644 index 0000000..488670d --- /dev/null +++ b/doc/asciidoctor.jam @@ -0,0 +1,50 @@ +# Copyright 2017 Peter Dimov +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import type ; +import scanner ; +import generators ; +import boostbook ; + +# File type + +type.register ASCIIDOC : asciidoc adoc ; + +# Define dependency scanner + +class asciidoc-scanner : common-scanner +{ + rule pattern ( ) + { + return "include::([^[]+)\\[" ; + } +} + +scanner.register asciidoc-scanner : include ; +type.set-scanner ASCIIDOC : asciidoc-scanner ; + +# Define generators + +generators.register-standard asciidoctor.asciidoc-to-html : ASCIIDOC : HTML ; +generators.register-standard asciidoctor.asciidoc-to-pdf : ASCIIDOC : PDF ; +# generators.register-standard asciidoctor.asciidoc-to-docbook : ASCIIDOC : DOCBOOK ; + +# Define actions + +actions asciidoc-to-html +{ + asciidoctor -b html -o $(1) $(2) +} + +actions asciidoc-to-pdf +{ + asciidoctor -r asciidoctor-pdf -b pdf -o $(1) $(2) +} + +actions asciidoc-to-docbook +{ + asciidoctor -b docbook -o $(1) $(2) +} diff --git a/doc/css/boostbook.css b/doc/css/boostbook.css deleted file mode 100644 index 28f8935..0000000 --- a/doc/css/boostbook.css +++ /dev/null @@ -1,716 +0,0 @@ - -/*============================================================================= -Copyright (c) 2004 Joel de Guzman -http://spirit.sourceforge.net/ - -Copyright 2013 Niall Douglas additions for colors and alignment. -Copyright 2013 Paul A. Bristow additions for more colors and alignments. - -Distributed under the Boost Software License, Version 1.0. (See accompany- -ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -=============================================================================*/ - -/*============================================================================= -Body defaults -=============================================================================*/ - - body - { - margin: 1em; - font-family: sans-serif; - } - -/*============================================================================= -Paragraphs -=============================================================================*/ - - p - { - text-align: left; - font-size: 10pt; - line-height: 1.15; - } - -/*============================================================================= -Program listings -=============================================================================*/ - - /* Code on paragraphs */ - p tt.computeroutput - { - font-size: 9pt; - } - - pre.synopsis - { - font-size: 9pt; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - - .programlisting, - .screen - { - font-size: 9pt; - display: block; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - - /* Program listings in tables don't get borders */ - td .programlisting, - td .screen - { - margin: 0pc 0pc 0pc 0pc; - padding: 0pc 0pc 0pc 0pc; - } - -/*============================================================================= -Headings -=============================================================================*/ - - h1, h2, h3, h4, h5, h6 - { - text-align: left; - margin: 1em 0em 0.5em 0em; - font-weight: bold; - } - - h1 { font-size: 140%; } - h2 { font-weight: bold; font-size: 140%; } - h3 { font-weight: bold; font-size: 130%; } - h4 { font-weight: bold; font-size: 120%; } - h5 { font-weight: normal; font-style: italic; font-size: 110%; } - h6 { font-weight: normal; font-style: italic; font-size: 100%; } - - /* Top page titles */ - title, - h1.title, - h2.title - h3.title, - h4.title, - h5.title, - h6.title, - .refentrytitle - { - font-weight: bold; - margin-bottom: 1pc; - } - - h1.title { font-size: 140% } - h2.title { font-size: 140% } - h3.title { font-size: 130% } - h4.title { font-size: 120% } - h5.title { font-size: 110% } - h6.title { font-size: 100% } - - .section h1 - { - margin: 0em 0em 0.5em 0em; - font-size: 140%; - } - - .section h2 { font-size: 140% } - .section h3 { font-size: 130% } - .section h4 { font-size: 120% } - .section h5 { font-size: 110% } - .section h6 { font-size: 100% } - - /* Code on titles */ - h1 tt.computeroutput { font-size: 140% } - h2 tt.computeroutput { font-size: 140% } - h3 tt.computeroutput { font-size: 130% } - h4 tt.computeroutput { font-size: 130% } - h5 tt.computeroutput { font-size: 130% } - h6 tt.computeroutput { font-size: 130% } - - -/*============================================================================= -Author -=============================================================================*/ - - h3.author - { - font-size: 100% - } - -/*============================================================================= -Lists -=============================================================================*/ - - li - { - font-size: 10pt; - line-height: 1.3; - } - - /* Unordered lists */ - ul - { - text-align: left; - } - - /* Ordered lists */ - ol - { - text-align: left; - } - -/*============================================================================= -Links -=============================================================================*/ - - a - { - text-decoration: none; /* no underline */ - } - - a:hover - { - text-decoration: underline; - } - -/*============================================================================= -Spirit style navigation -=============================================================================*/ - - .spirit-nav - { - text-align: right; - } - - .spirit-nav a - { - color: white; - padding-left: 0.5em; - } - - .spirit-nav img - { - border-width: 0px; - } - -/*============================================================================= -Copyright footer -=============================================================================*/ - .copyright-footer - { - text-align: right; - font-size: 70%; - } - - .copyright-footer p - { - text-align: right; - font-size: 80%; - } - -/*============================================================================= -Table of contents -=============================================================================*/ - - div.toc - { - margin: 1pc 4% 0pc 4%; - padding: 0.1pc 1pc 0.1pc 1pc; - font-size: 80%; - line-height: 1.15; - } - - .boost-toc - { - float: right; - padding: 0.5pc; - } - - /* Code on toc */ - .toc .computeroutput { font-size: 120% } - - /* No margin on nested menus */ - - .toc dl dl { margin: 0; } - -/*============================================================================= -Tables -=============================================================================*/ - - .table-title, - div.table p.title - { - margin-left: 4%; - padding-right: 0.5em; - padding-left: 0.5em; - } - - .informaltable table, - .table table - { - width: 92%; - margin-left: 4%; - margin-right: 4%; - } - - div.informaltable table, - div.table table - { - padding: 4px; - } - - /* Table Cells */ - div.informaltable table tr td, - div.table table tr td - { - padding: 0.5em; - text-align: left; - font-size: 9pt; - } - - div.informaltable table tr th, - div.table table tr th - { - padding: 0.5em 0.5em 0.5em 0.5em; - border: 1pt solid white; - font-size: 80%; - } - - table.simplelist - { - width: auto !important; - margin: 0em !important; - padding: 0em !important; - border: none !important; - } - table.simplelist td - { - margin: 0em !important; - padding: 0em !important; - text-align: left !important; - font-size: 9pt !important; - border: none !important; - } - -/*============================================================================= -Suppress margins in tables -=============================================================================*/ - - table th > *:first-child, - table td > *:first-child - { - margin-top: 0; - } - - table th > *:last-child, - table td > *:last-child - { - margin-bottom: 0; - } - -/*============================================================================= -Blurbs -=============================================================================*/ - - div.note, - div.tip, - div.important, - div.caution, - div.warning, - p.blurb - { - font-size: 9pt; /* A little bit smaller than the main text */ - line-height: 1.2; - display: block; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - - p.blurb img - { - padding: 1pt; - } - -/*============================================================================= -Variable Lists -=============================================================================*/ - - div.variablelist - { - margin: 1em 0; - } - - /* Make the terms in definition lists bold */ - div.variablelist dl dt, - span.term - { - font-weight: bold; - font-size: 10pt; - } - - div.variablelist table tbody tr td - { - text-align: left; - vertical-align: top; - padding: 0em 2em 0em 0em; - font-size: 10pt; - margin: 0em 0em 0.5em 0em; - line-height: 1; - } - - div.variablelist dl dt - { - margin-bottom: 0.2em; - } - - div.variablelist dl dd - { - margin: 0em 0em 0.5em 2em; - font-size: 10pt; - } - - div.variablelist table tbody tr td p, - div.variablelist dl dd p - { - margin: 0em 0em 0.5em 0em; - line-height: 1; - } - -/*============================================================================= -Misc -=============================================================================*/ - - /* Title of books and articles in bibliographies */ - span.title - { - font-style: italic; - } - - span.underline - { - text-decoration: underline; - } - - span.strikethrough - { - text-decoration: line-through; - } - - /* Copyright, Legal Notice */ - div div.legalnotice p - { - text-align: left - } - -/*============================================================================= -Colors -=============================================================================*/ - - @media screen - { - body { - background-color: #FFFFFF; - color: #000000; - } - - /* Syntax Highlighting */ - .keyword { color: #0000AA; } - .identifier { color: #000000; } - .special { color: #707070; } - .preprocessor { color: #402080; } - .char { color: teal; } - .comment { color: #800000; } - .string { color: teal; } - .number { color: teal; } - .white_bkd { background-color: #FFFFFF; } - .dk_grey_bkd { background-color: #999999; } - - /* Links */ - a, a .keyword, a .identifier, a .special, a .preprocessor - a .char, a .comment, a .string, a .number - { - color: #005a9c; - } - - a:visited, a:visited .keyword, a:visited .identifier, - a:visited .special, a:visited .preprocessor a:visited .char, - a:visited .comment, a:visited .string, a:visited .number - { - color: #9c5a9c; - } - - h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, - h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, - h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited - { - text-decoration: none; /* no underline */ - color: #000000; - } - - /* Copyright, Legal Notice */ - .copyright - { - color: #666666; - font-size: small; - } - - div div.legalnotice p - { - color: #666666; - } - - /* Program listing */ - pre.synopsis - { - border: 1px solid #DCDCDC; - } - - .programlisting, - .screen - { - border: 1px solid #DCDCDC; - } - - td .programlisting, - td .screen - { - border: 0px solid #DCDCDC; - } - - /* Blurbs */ - div.note, - div.tip, - div.important, - div.caution, - div.warning, - p.blurb - { - border: 1px solid #DCDCDC; - } - - /* Table of contents */ - div.toc - { - border: 1px solid #DCDCDC; - } - - /* Tables */ - div.informaltable table tr td, - div.table table tr td - { - border: 1px solid #DCDCDC; - } - - div.informaltable table tr th, - div.table table tr th - { - background-color: #F0F0F0; - border: 1px solid #DCDCDC; - } - - .copyright-footer - { - color: #8F8F8F; - } - - /* Misc */ - span.highlight - { - color: #00A000; - } - } - - @media print - { - /* Links */ - a - { - color: black; - } - - a:visited - { - color: black; - } - - .spirit-nav - { - display: none; - } - - /* Program listing */ - pre.synopsis - { - border: 1px solid gray; - } - - .programlisting, - .screen - { - border: 1px solid gray; - } - - td .programlisting, - td .screen - { - border: 0px solid #DCDCDC; - } - - /* Table of contents */ - div.toc - { - border: 1px solid gray; - } - - .informaltable table, - .table table - { - border: 1px solid gray; - border-collapse: collapse; - } - - /* Tables */ - div.informaltable table tr td, - div.table table tr td - { - border: 1px solid gray; - } - - div.informaltable table tr th, - div.table table tr th - { - border: 1px solid gray; - } - - table.simplelist tr td - { - border: none !important; - } - - /* Misc */ - span.highlight - { - font-weight: bold; - } - } - -/*============================================================================= -Images -=============================================================================*/ - - span.inlinemediaobject img - { - vertical-align: middle; - } - -/*============================================================================== -Super and Subscript: style so that line spacing isn't effected, see -http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 -==============================================================================*/ - -sup, -sub { -height: 0; -line-height: 1; -vertical-align: baseline; -position: relative; - -} - -/* For internet explorer: */ - -* html sup, -* html sub { -vertical-align: bottom; -} - -sup { -bottom: 1ex; -} - -sub { -top: .5ex; -} - -/*============================================================================== -Indexes: pretty much the same as the TOC. -==============================================================================*/ - - .index - { - font-size: 80%; - padding-top: 0px; - padding-bottom: 0px; - margin-top: 0px; - margin-bottom: 0px; - margin-left: 0px; - } - - .index ul - { - padding-left: 3em; - } - - .index p - { - padding: 2px; - margin: 2px; - } - - .index-entry-level-0 - { - font-weight: bold; - } - - .index em - { - font-weight: bold; - } - - -/*============================================================================== -Alignment and coloring use 'role' feature, available from Quickbook 1.6 up. -Added from Niall Douglas for role color and alignment. -http://article.gmane.org/gmane.comp.lib.boost.devel/243318 -*/ - -/* Add text alignment (see http://www.w3schools.com/cssref/pr_text_text-align.asp) */ -span.aligncenter -{ - display: inline-block; width: 100%; text-align: center; -} -span.alignright -{ - display: inline-block; width: 100%; text-align: right; -} -/* alignleft is the default. */ -span.alignleft -{ - display: inline-block; width: 100%; text-align: left; -} - -/* alignjustify stretches the word spacing so that each line has equal width -within a chosen fraction of page width (here arbitrarily 20%). -*Not* useful inside table items as the column width remains the total string width. -Nor very useful, except to temporarily restrict the width. -*/ -span.alignjustify -{ - display: inline-block; width: 20%; text-align: justify; -} - -/* Text colors. -Names at http://www.w3.org/TR/2002/WD-css3-color-20020219/ 4.3. X11 color keywords. -Quickbook Usage: [role red Some red text] - -*/ -span.red { inline-block; color: red; } -span.green { color: green; } -span.lime { color: #00FF00; } -span.blue { color: blue; } -span.navy { color: navy; } -span.yellow { color: yellow; } -span.magenta { color: magenta; } -span.indigo { color: #4B0082; } -span.cyan { color: cyan; } -span.purple { color: purple; } -span.gold { color: gold; } -span.silver { color: silver; } /* lighter gray */ -span.gray { color: #808080; } /* light gray */ diff --git a/doc/html/mp11.html b/doc/html/mp11.html index e6c7b5c..2a9c058 100644 --- a/doc/html/mp11.html +++ b/doc/html/mp11.html @@ -1,2532 +1,2854 @@ - + + - -Chapter 1. Boost.Mp11 - - - + + + + + +Boost.Mp11 + + - - - - - - - - -
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
-
-
-
-
-

-Chapter 1. Boost.Mp11

-
-
-

- Distributed under the Boost - Software License, Version 1.0. -

-
-
-
-

Table of Contents

-
-
Overview
-
Definitions
-
Examples
-
-
Generating Test - Cases
-
Writing - common_type specializations
-
Fixing tuple_cat
-
Computing Return - Types
-
-
Reference
-
-
Integral Constants, <boost/mp11/integral.hpp>
-
-
mp_bool<B>
-
mp_true
-
mp_false
-
mp_to_bool<T>
-
mp_not<T>
-
mp_int<I>
-
mp_size_t<N>
-
-
List Operations, <boost/mp11/list.hpp>
-
-
mp_list<T...>
-
mp_size<L>
-
mp_empty<L>
-
mp_front<L>
-
mp_pop_front<L>
-
mp_first<L>
-
mp_rest<L>
-
mp_second<L>
-
mp_third<L>
-
mp_push_front<L, T...>
-
mp_push_back<L, T...>
-
mp_rename<L, - Y>
-
mp_apply<F, - L>
-
mp_apply_q<Q, - L>
-
mp_append<L...>
-
mp_replace_front<L, T>
-
mp_replace_first<L, T>
-
mp_replace_second<L, T>
-
mp_replace_third<L, T>
-
-
Utility Components, <boost/mp11/utility.hpp>
-
-
mp_identity<T>
-
mp_identity_t<T>
-
mp_inherit<T...>
-
mp_if_c<C, T, E...>
-
mp_if<C, - T, E...>
-
mp_eval_if_c<C, T, F, - U...>
-
mp_eval_if<C, T, F, - U...>
-
mp_eval_if_q<C, T, Q, - U...>
-
mp_valid<F, T...>
-
mp_defer<F, T...>
-
mp_quote<F>
-
mp_invoke<Q, T...>
-
-
Algorithms, <boost/mp11/algorithm.hpp>
-
-
mp_assign<L1, L2>
-
mp_clear<L>
-
mp_transform<F, L...>
-
mp_transform_q<Q, L...>
-
mp_transform_if<P, F, L...>
-
mp_transform_if_q<Qp, Qf, L...>
-
mp_fill<L, V>
-
mp_count<L, V>
-
mp_count_if<L, P>
-
mp_contains<L, V>
-
mp_repeat_c<L, N>
-
mp_repeat<L, N>
-
mp_product<F, L...>
-
mp_product_q<Q, L...>
-
mp_drop_c<L, N>
-
mp_drop<L, N>
-
mp_iota_c<N>
-
mp_iota<N>
-
mp_at_c<L, I>
-
mp_at<L, - I>
-
mp_take_c<L, N>
-
mp_take<L, N>
-
mp_insert_c<L, I, T...>
-
mp_insert<L, I, T...>
-
mp_erase_c<L, I, J>
-
mp_erase<L, I, J>
-
mp_replace<L, V, W>
-
mp_replace_if<L, P, W>
-
mp_replace_at_c<L, I, W>
-
mp_replace_at<L, I, W>
-
mp_copy_if<L, P>
-
mp_remove<L, V>
-
mp_remove_if<L, P>
-
mp_partition<L, P>
-
mp_sort<L, P>
-
mp_find<L, V>
-
mp_find_if<L, P>
-
mp_reverse<L>
-
mp_fold<L, V, F>
-
mp_reverse_fold<L, V, F>
-
mp_unique<L>
-
mp_all_of<L, P>
-
mp_none_of<L, P>
-
mp_any_of<L, P>
-
mp_for_each<L>(f)
-
mp_with_index<N>(i, f)
-
-
Set Operations, <boost/mp11/set.hpp>
-
-
mp_set_contains<S, V>
-
mp_set_push_back<S, T...>
-
mp_set_push_front<S, T...>
-
-
Map Operations, <boost/mp11/map.hpp>
-
-
mp_map_find<M, - K>
-
mp_map_contains<M, K>
-
mp_map_insert<M, T>
-
mp_map_replace<M, T>
-
mp_map_update<M, T, F>
-
mp_map_erase<M, K>
-
-
Helper Metafunctions, <boost/mp11/function.hpp>
-
-
mp_void<T...>
-
mp_and<T...>
-
mp_all<T...>
-
mp_or<T...>
-
mp_any<T...>
-
mp_same<T...>
-
mp_plus<T...>
-
-
Bind, <boost/mp11/bind.hpp>
-
-
mp_arg<I>
-
_1, - ..., _9
-
mp_bind<F, - T...>
-
mp_bind_q<Q, - T...>
-
mp_bind_front<F, T...>
-
mp_bind_front_q<Q, T...>
-
mp_bind_back<F, T...>
-
mp_bind_back_q<Q, T...>
-
-
Integer Sequences, - <boost/mp11/integer_sequence.hpp>
-
-
integer_sequence<T, I...>
-
make_integer_sequence<T, N>
-
index_sequence<I...>
-
make_index_sequence<N>
-
index_sequence_for<T...>
-
-
A "for each" - algorithm for tuple-like types, <boost/mp11/tuple_for_each.hpp>
-
tuple_for_each(tp, f)
-
-
-
-
- -

- Mp11 is a C++11 metaprogramming library based on template aliases and variadic - templates. It implements the approach outlined in the article Simple - C++11 metaprogramming and its - sequel. Reading these articles before proceeding with this documentation - is highly recommended. -

-

- The general principles upon which Mp11 is built are that algorithms and metafunctions - are template aliases of the form F<T...> - and data structures are lists of the form L<T...>, - with the library placing no requirements on L. - mp_list<T...> - is the built-in list type, but std::tuple<T...>, - std::pair<T1, T2> and std::variant<T...> - are also perfectly legitimate list types, although of course std::pair<T1, - T2>, - due to having exactly two elements, is not resizeable and will consequently - not work with algorithms that need to add or remove elements. -

-

- Another distinguishing feature of this approach is that lists (L<T...>) have the same form as metafunctions - (F<T...>) - and can therefore be used as such. For example, applying std::add_pointer_t - to the list std::tuple<int, float> by way of mp_transform<std::add_pointer_t, - std::tuple<int, float>> gives us std::tuple<int*, float*>, but we can also apply mp_list - to the same tuple: -

-
using R = mp_transform<mp_list, std::tuple<int, float>>;
-
-

- and get std::tuple<mp_list<int>, mp_list<float>>. -

-
-
- -

- A list is a — usually but not necessarily variadic — template - class whose parameters are all types, for example mp_list<char[], - void>, - mp_list<>, - std::tuple<int, float, char>, - std::pair<int, float>, std::shared_ptr<X>. -

-

- A metafunction is a class template or a template alias - whose parameters are all types, for example std::add_pointer_t, - std::is_const, mp_second, - mp_push_front, mp_list, std::tuple, - std::pair, std::shared_ptr, - or -

-
template<class...> using F1 = void;
-template<class T> using F2 = T*;
-template<class... T> using F3 = std::integral_constant<std::size_t, sizeof...(T)>;
-
-

- A quoted metafunction is a class with a public metafunction - member called fn, for example -

-
struct Q1 { template<class...> using fn = void; };
-struct Q2 { template<class T> using fn = T*; };
-struct Q3 { template<class... T> using fn = std::integral_constant<std::size_t, sizeof...(T)>; };
-
-

- An integral constant type is a class with a public member - value that is an integral constant - in the C++ sense. For example, std::integral_constant<int, - 7>, - or -

-
struct N { static int constexpr value = 2; };
-
-

- A set is a list whose elements are unique. -

-

- A map is a list of lists, the inner lists having at least - one element (the key.) The keys of the map must be unique. For example, -

-
using M1 = std::tuple<std::pair<int, int*>, std::pair<float, float*>, std::pair<void, void*>>;
-using M2 = mp_list<mp_list<int, int*>, mp_list<float>, mp_list<char, char[1], char[2]>>;
-
-
-
- -
- -

- Let's suppose that we have written a metafunction result<T, - U>: -

-
template<class T> using promote = typename std::common_type<T, int>::type;
-template<class T, class U> using result = typename std::common_type<promote<T>, promote<U>>::type;
-
-

- that ought to represent the result of an arithmetic operation on the integer - types T and U, for example t - + u. - We want to test whether result<T, - U> - gives correct results for various combinations of T - and U, so we write the function -

-
template<class T1, class T2> void test_result()
-{
-    using T3 = decltype( T1() + T2() );
-    using T4 = result<T1, T2>;
-
-    std::cout << ( std::is_same<T3, T4>::value? "[PASS]": "[FAIL]" ) << std::endl;
-}
-
-

- and then need to call it a substantial number of times: -

-
int main()
-{
-    test_result<char, char>();
-    test_result<char, short>();
-    test_result<char, int>();
-    test_result<char, unsigned>();
-    // ...
-}
-
-

- Writing all those type combinations by hand is unwieldy, error prone, and - worst of all, boring. This is how we can leverage Mp11 to automate the task: -

-
#include <boost/mp11.hpp>
-#include <boost/core/demangle.hpp>
-#include <type_traits>
-#include <iostream>
-#include <typeinfo>
-
-using namespace boost::mp11;
-
-template<class T> std::string name()
-{
-    return boost::core::demangle( typeid(T).name() );
-}
-
-template<class T> using promote = typename std::common_type<T, int>::type;
-template<class T, class U> using result = typename std::common_type<promote<T>, promote<U>>::type;
-
-template<class T1, class T2> void test_result( mp_list<T1, T2> const& )
-{
-    using T3 = decltype( T1() + T2() );
-    using T4 = result<T1, T2>;
-
-    std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " )
-        << name<T1>() << " + " << name<T2>() << " -> " << name<T3>() << ", result: " << name<T4>() << std::endl;
-}
-
-int main()
-{
-    using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
-    tuple_for_each( mp_product<mp_list, L, L>(), [](auto&& x){ test_result(x); } );
-}
-
-

- How does it work? -

-

- mp_product<F, L1, L2> - calls F<T1, T2> where T1 - varies over the elements of L1 - and T2 varies over the elements - of L2, as if by executing - two nested loops. It then returns a list of these results, of the same type - as L1. -

-

- In our case, both lists are the same std::tuple, - and F is mp_list, - so mp_product<mp_list, L, L> will get us std::tuple<mp_list<char, - char>, - mp_list<char, short>, mp_list<char, - int>, - ..., mp_list<unsigned long, long>, mp_list<unsigned long, unsigned - long>>. -

-

- We then default-construct this tuple and pass it to tuple_for_each. - tuple_for_each(tp, f) calls f - for every tuple element; we use a (C++14) lambda that calls test_result. -

-

- In pure C++11, we can't use a lambda with an auto&& parameter, so we'll have to make - test_result a function object - with a templated operator() - and pass that to tuple_for_each - directly: -

-
struct test_result
-{
-    template<class T1, class T2> void operator()( mp_list<T1, T2> const& ) const
-    {
-        using T3 = decltype( T1() + T2() );
-        using T4 = result<T1, T2>;
-
-        std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " )
-            << name<T1>() << " + " << name<T2>() << " -> " << name<T3>() << ", result: " << name<T4>() << std::endl;
-    }
-};
-
-int main()
-{
-    using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
-    tuple_for_each( mp_product<mp_list, L, L>(), test_result() );
-}
-
-
-
- -

- The standard trait std::common_type, used to obtain a type to which - all of its arguments can convert without unnecessary loss of precision, can - be user-specialized when its default implementation (based on the ternary - ?: operator) is unsuitable. -

-

- Let's write a common_type - specialization for two std::tuple - arguments. For that, we need a metafunction that applies std::common_type - to each pair of elements and gathers the results into a tuple: -

-
template<class... T> using common_type_t = typename std::common_type<T...>::type; // standard in C++14
-
-template<class Tp1, class Tp2> using common_tuple = mp_transform<common_type_t, Tp1, Tp2>;
-
-

- then specialize common_type - to use it: -

-
namespace std
-{
-
-    template<class... T1, class... T2> struct common_type<std::tuple<T1...>, std::tuple<T2...>>: mp_defer<common_tuple, std::tuple<T1...>, std::tuple<T2...>>
-    {
-    };
+
+
+
+
+

Overview

+
+
+

Mp11 is a C++11 metaprogramming library based on template aliases and variadic templates. +It implements the approach outlined in the article +"Simple C++ metaprogramming" +and its sequel. Reading these +articles before proceeding with this documentation is highly recommended.

+
+
+

The general principles upon which Mp11 is built are that algorithms and metafunctions are +template aliases of the form F<T…​> and data structures are lists of the form L<T…​>, +with the library placing no requirements on L. mp_list<T…​> is the built-in list type, +but std::tuple<T…​>, std::pair<T1, T2> and std::variant<T…​> are also perfectly +legitimate list types, although of course std::pair<T1, T2>, due to having exactly two elements, +is not resizeable and will consequently not work with algorithms that need to add or remove +elements.

+
+
+

Another distinguishing feature of this approach is that lists (L<T…​>) have the same form as +metafunctions (F<T…​>) and can therefore be used as such. For example, applying std::add_pointer_t +to the list std::tuple<int, float> by way of mp_transform<std::add_pointer_t, std::tuple<int, float>> +gives us std::tuple<int*, float*>, but we can also apply mp_list to the same tuple:

+
+
+
+
using R = mp_transform<mp_list, std::tuple<int, float>>;
+
+
+
+

and get std::tuple<mp_list<int>, mp_list<float>>.

+
+
+
+
+

Definitions

+
+
+

A list is a — usually but not necessarily variadic — template class whose parameters are all types, +for example mp_list<char[], void>, mp_list<>, std::tuple<int, float, char>, std::pair<int, float>, std::shared_ptr<X>.

+
+
+

A metafunction is a class template or a template alias whose parameters are all types, for example std::add_pointer_t, +std::is_const, mp_second, mp_push_front, mp_list, std::tuple, std::pair, std::shared_ptr, or

+
+
+
+
template<class...> using F1 = void;
+template<class T> using F2 = T*;
+template<class... T> using F3 = std::integral_constant<std::size_t, sizeof...(T)>;
+
+
+
+

A quoted metafunction is a class with a public metafunction member called fn, for example

+
+
+
+
struct Q1 { template<class...> using fn = void; };
+struct Q2 { template<class T> using fn = T*; };
+struct Q3 { template<class... T> using fn = std::integral_constant<std::size_t, sizeof...(T)>; };
+
+
+
+

An integral constant type is a class with a public member value that is an integral constant in the C++ sense. For example, +std::integral_constant<int, 7>, or

+
+
+
+
struct N { static int constexpr value = 2; };
+
+
+
+

A set is a list whose elements are unique.

+
+
+

A map is a list of lists, the inner lists having at least one element (the key.) The keys of the map must be unique. For example,

+
+
+
+
using M1 = std::tuple<std::pair<int, int*>, std::pair<float, float*>, std::pair<void, void*>>;
+using M2 = mp_list<mp_list<int, int*>, mp_list<float>, mp_list<char, char[1], char[2]>>;
+
+
+
+
+
+

Examples

+
+
+

Generating Test Cases

+
+

Let’s suppose that we have written a metafunction result<T, U>:

+
+
+
+
template<class T> using promote = typename std::common_type<T, int>::type;
 
-} // std
-
-

- (There is no need to specialize std::common_type - for more than two arguments - it takes care of synthesizing the appropriate - semantics from the binary case.) -

-

- The subtlety here is the use of mp_defer. - We could have defined a nested type - to common_tuple<std::tuple<T1...>, std::tuple<T2...>>, and it would still have worked - in all valid cases. By letting mp_defer - define type, though, we make - our specialization SFINAE-friendly. -

-

- That is, when our common_tuple - causes a substitution failure instead of a hard error, mp_defer - will not define a nested type, - and common_type_t, which - is defined as typename common_type<...>::type, - will also cause a substitution failure. -

-

- As another example, consider the hypothetical type expected<T, - E...> - that represents either a successful return with a value of T, or an unsucessful return with an error - code of some type in the list E.... The common type of expected<T1, E1, - E2, E3> - and expected<T2, E1, E4, - E5> - is expected<common_type_t<T1, T2>, E1, E2, - E3, E4, E5>. That is, the possible return values - are combined into their common type, and we take the union of the set of - error types. -

-

- Therefore, -

-
template<class T1, class E1, class T2, class E2> using common_expected = mp_rename<mp_push_front<mp_unique<mp_append<E1, E2>>, common_type_t<T1, T2>>, expected>;
+template<class T, class U> using result =
+    typename std::common_type<promote<T>, promote<U>>::type;
+
+
+
+

that ought to represent the result of an arithmetic operation on the integer types T and U, +for example t + u. We want to test whether result<T, U> gives correct results for various combinations +of T and U, so we write the function

+
+
+
+
template<class T1, class T2> void test_result()
+{
+    using T3 = decltype( T1() + T2() );
+    using T4 = result<T1, T2>;
 
-namespace std
-{
+    std::cout << ( std::is_same<T3, T4>::value? "[PASS]": "[FAIL]" ) << std::endl;
+}
+
+
+
+

and then need to call it a substantial number of times:

+
+
+
+
int main()
+{
+    test_result<char, char>();
+    test_result<char, short>();
+    test_result<char, int>();
+    test_result<char, unsigned>();
+    // ...
+}
+
+
+
+

Writing all those type combinations by hand is unwieldy, error prone, and worst of all, boring. This is +how we can leverage Mp11 to automate the task:

+
+
+
+
#include <boost/mp11.hpp>
+#include <boost/core/demangle.hpp>
+#include <type_traits>
+#include <iostream>
+#include <typeinfo>
 
-    template<class T1, class... E1, class T2, class... E2> struct common_type<expected<T1, E1...>, expected<T2, E2...>>: mp_defer<common_expected, T1, mp_list<E1...>, T2, mp_list<E2...>>
-    {
-    };
+using namespace boost::mp11;
 
-} // std
-
-

- Here we've taken a different tack; instead of passing the expected - types to common_expected, - we're passing the T types - and lists of the E types. - This makes our job easier. mp_unique<mp_append<E1, E2>> - gives us the concatenation of E1 - and E2 with the duplicates - removed; we then add common_type_t<T1, T2> - to the front via mp_push_front; - and finally, we mp_rename - the resultant mp_list to - expected. -

-
-
- -

- The article Simple - C++11 metaprogramming builds an implementation of the standard function - tuple_cat, with the end result - given below: -

-
template<class L> using F = mp_iota<mp_size<L>>;
+template<class T> std::string name()
+{
+    return boost::core::demangle( typeid(T).name() );
+}
 
-template<class R, class...Is, class... Ks, class Tp>
-R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
-{
-    return R{ std::get<Ks::value>(std::get<Is::value>(tp))... };
-}
+template<class T> using promote = typename std::common_type<T, int>::type;
 
-template<class... Tp,
-    class R = mp_append<std::tuple<>, typename std::remove_reference<Tp>::type...>>
-    R tuple_cat( Tp &&... tp )
-{
-    std::size_t const N = sizeof...(Tp);
+template<class T, class U> using result =
+    typename std::common_type<promote<T>, promote<U>>::type;
 
-    // inner
+template<class T1, class T2> void test_result( mp_list<T1, T2> const& )
+{
+    using T3 = decltype( T1() + T2() );
+    using T4 = result<T1, T2>;
 
-    using list1 = mp_list<mp_rename<typename std::remove_reference<Tp>::type, mp_list>...>;
-    using list2 = mp_iota_c<N>;
+    std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " )
+        << name<T1>() << " + " << name<T2>() << " -> " << name<T3>()
+        << ", result: " << name<T4>() << std::endl;
+}
 
-    using list3 = mp_transform<mp_fill, list1, list2>;
+int main()
+{
+    using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
+    tuple_for_each( mp_product<mp_list, L, L>(), [](auto&& x){ test_result(x); } );
+}
+
+
+
+

How does it work?

+
+
+

mp_product<F, L1, L2> calls F<T1, T2> where T1 varies over the elements of L1 and T2 varies over +the elements of L2, as if by executing two nested loops. It then returns a list of these results, of the same +type as L1.

+
+
+

In our case, both lists are the same std::tuple, and F is mp_list, so mp_product<mp_list, L, L> will get us +std::tuple<mp_list<char, char>, mp_list<char, short>, mp_list<char, int>, …​, mp_list<unsigned long, long>, mp_list<unsigned long, unsigned long>>.

+
+
+

We then default-construct this tuple and pass it to tuple_for_each. tuple_for_each(tp, f) calls f for every +tuple element; we use a (C++14) lambda that calls test_result.

+
+
+

In pure C++11, we can’t use a lambda with an auto&& parameter, so we’ll have to make test_result a function object with +a templated operator() and pass that to tuple_for_each directly:

+
+
+
+
struct test_result
+{
+    template<class T1, class T2> void operator()( mp_list<T1, T2> const& ) const
+    {
+        using T3 = decltype( T1() + T2() );
+        using T4 = result<T1, T2>;
+
+        std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " )
+            << name<T1>() << " + " << name<T2>() << " -> " << name<T3>()
+            << ", result: " << name<T4>() << std::endl;
+    }
+};
 
-    using inner = mp_apply<mp_append, list3>;
+int main()
+{
+    using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
+    tuple_for_each( mp_product<mp_list, L, L>(), test_result() );
+}
+
+
+
+
+

Writing common_type specializations

+
+

The standard trait std::common_type, used to obtain a type to which all of its arguments can convert without +unnecessary loss of precision, can be user-specialized when its default implementation (based on the ternary ?: +operator) is unsuitable.

+
+
+

Let’s write a common_type specialization for two std::tuple arguments. For that, we need a metafunction that +applies std::common_type to each pair of elements and gathers the results into a tuple:

+
+
+
+
template<class... T> using common_type_t =
+    typename std::common_type<T...>::type; // standard in C++14
 
-    // outer
+template<class Tp1, class Tp2> using common_tuple =
+    mp_transform<common_type_t, Tp1, Tp2>;
+
+
+
+

then specialize common_type to use it:

+
+
+
+
namespace std
+{
 
-    using list4 = mp_transform<F, list1>;
+    template<class... T1, class... T2>
+    struct common_type<std::tuple<T1...>, std::tuple<T2...>>:
+        mp_defer<common_tuple, std::tuple<T1...>, std::tuple<T2...>>
+    {
+    };
 
-    using outer = mp_apply<mp_append, list4>;
+} // std
+
+
+
+

(There is no need to specialize std::common_type for more than two arguments - it takes care of synthesizing the appropriate semantics from +the binary case.)

+
+
+

The subtlety here is the use of mp_defer. We could have defined a nested type to common_tuple<std::tuple<T1…​>, std::tuple<T2…​>>, +and it would still have worked in all valid cases. By letting mp_defer define type, though, we make our specialization SFINAE-friendly.

+
+
+

That is, when our common_tuple causes a substitution failure instead of a hard error, mp_defer will not define a nested type, +and common_type_t, which is defined as typename common_type<…​>::type, will also cause a substitution failure.

+
+
+

As another example, consider the hypothetical type expected<T, E…​> that represents either a successful return with a value of T, +or an unsucessful return with an error code of some type in the list E…​. The common type of expected<T1, E1, E2, E3> and +expected<T2, E1, E4, E5> is expected<common_type_t<T1, T2>, E1, E2, E3, E4, E5>. That is, the possible return values are +combined into their common type, and we take the union of the set of error types.

+
+
+

Therefore,

+
+
+
+
template<class T1, class E1, class T2, class E2> using common_expected =
+    mp_rename<mp_push_front<mp_unique<mp_append<E1, E2>>, common_type_t<T1, T2>>, expected>;
 
-    //
+namespace std
+{
 
-    return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) );
-}
-
-

- This function, however, is not entirely correct, in that it doesn't handle - some cases properly. For example, trying to concatenate tuples containing - move-only elements such as unique_ptr - fails: -

-
std::tuple<std::unique_ptr<int>> t1;
-std::tuple<std::unique_ptr<float>> t2;
+    template<class T1, class... E1, class T2, class... E2>
+    struct common_type<expected<T1, E1...>, expected<T2, E2...>>:
+        mp_defer<common_expected, T1, mp_list<E1...>, T2, mp_list<E2...>>
+    {
+    };
 
-auto result = ::tuple_cat( std::move( t1 ), std::move( t2 ) );
-
-

- Trying to concatenate const - tuples fails: -

-
std::tuple<int> const t1;
-std::tuple<float> const t2;
+} // std
+
+
+
+

Here we’ve taken a different tack; instead of passing the expected types to common_expected, we’re passing the T types and lists of +the E types. This makes our job easier. mp_unique<mp_append<E1, E2>> gives us the concatenation of E1 and E2 with the duplicates +removed; we then add common_type_t<T1, T2> to the front via mp_push_front; and finally, we mp_rename the resultant mp_list +to expected.

+
+
+
+

Fixing tuple_cat

+
+

The article Simple C++11 metaprogramming builds an +implementation of the standard function tuple_cat, with the end result given below:

+
+
+
+
template<class L> using F = mp_iota<mp_size<L>>;
 
-auto result = ::tuple_cat( t1, t2 );
-
-

- And finally, the standard tuple_cat - is specified to work on arbitrary tuple-like types (that is, all types that - support tuple_size, tuple_element, and get), - while our implementation only works with tuple - and pair. std::array, - for example, fails: -

-
std::array<int, 2> t1{ 1, 2 };
-std::array<float, 3> t2{ 3.0f, 4.0f, 5.0f };
+template<class R, class...Is, class... Ks, class Tp>
+R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
+{
+    return R{ std::get<Ks::value>(std::get<Is::value>(tp))... };
+}
 
-auto result = ::tuple_cat( t1, t2 );
-
-

- Let's fix these one by one. Support for move-only types is easy, if one knows - where to look. The problem is that Tp - that we're passing to the helper tuple_cat_ - is (correctly) tuple<unique_ptr<int>&&, - unique_ptr<float>&&>, - but std::get<0>(tp) still returns unique_ptr<int>&, - because tp is an lvalue. - This behavior is a bit surprising, but consistent with how rvalue reference - members are treated by the language. -

-

- Long story short, we need std::move(tp) - in tuple_cat_ to make tp an rvalue: -

-
template<class R, class...Is, class... Ks, class Tp>
-R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
-{
-    return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
-}
-
-

- Next, const-qualified tuples. - The issue here is that we're stripping references from the input tuples, - but not const. As a result, - we're trying to manipulate types such as tuple<int> - const with Mp11 algorithms, and these - types do not fit the list concept. We just need to strip qualifiers as well, - by defining the useful remove_cv_ref - primitive that is inexplicably missing from the standard library: -

-
template<class T> using remove_cv_ref = typename std::remove_cv<
-    typename std::remove_reference<T>::type>::type;
-
-

- and then by using remove_cv_ref<Tp> in place of typename - std::remove_reference<Tp>::type: -

-
template<class... Tp,
-    class R = mp_append<std::tuple<>, remove_cv_ref<Tp>...>>
-    R tuple_cat( Tp &&... tp )
-{
-    std::size_t const N = sizeof...(Tp);
+template<class... Tp,
+    class R = mp_append<std::tuple<>, typename std::remove_reference<Tp>::type...>>
+    R tuple_cat( Tp &&... tp )
+{
+    std::size_t const N = sizeof...(Tp);
 
-    // inner
+    // inner
 
-    using list1 = mp_list<mp_rename<remove_cv_ref<Tp>, mp_list>...>;
+    using list1 = mp_list<mp_rename<typename std::remove_reference<Tp>::type, mp_list>...>;
+    using list2 = mp_iota_c<N>;
 
-    // ...
-
-

- Finally, tuple-like types. We've so far exploited the fact that std::pair - and std::tuple are valid Mp11 lists, but in general, - arbitrary tuple-like types aren't, so we need to convert them into such. - For that, we'll need to define a metafunction from_tuple_like - that will take an arbitrary tuple-like type and will return, in our case, - the corresponding mp_list. -

-

- Technically, a more principled approach would've been to return std::tuple, - but here mp_list will prove - more convenient. -

-

- What we need is, given a tuple-like type Tp, - to obtain mp_list<std::tuple_element<0, - Tp>::type, std::tuple_element<1, - Tp>::type, ..., std::tuple_element<N-1, Tp>::type>, where N - is tuple_size<Tp>::value. Here's one way to do it: -

-
template<class T, class I> using tuple_element = typename std::tuple_element<I::value, T>::type;
-template<class T> using from_tuple_like = mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
-
-

- (mp_iota<N> is - an algorithm that returns an mp_list - with elements mp_size_t<0>, mp_size_t<1>, ..., - mp_size_t<N-1>.) -

-

- Remember that mp_product<F, - L1, L2> - performs the equivalent of two nested loops over the elements of L1 and L2, - applying F to the two variables - and gathering the result. In our case L1 - consists of the single element T, - so only the second loop (over mp_iota<N>, - where N is tuple_size<T>), - remains, and we get a list of the same type as L1 - (an mp_list) with contents - tuple_element<T, mp_size_t<0>>, - tuple_element<T, mp_size_t<1>>, - ..., tuple_element<T, mp_size_t<N-1>>. -

-

- For completeness's sake, here's another, more traditional way to achieve - the same result: -

-
template<class T> using from_tuple_like = mp_transform_q<mp_bind_front<tuple_element, T>, mp_iota<std::tuple_size<T>>>;
-
-

- With all these fixes applied, our fully operational tuple_cat - now looks like this: -

-
template<class L> using F = mp_iota<mp_size<L>>;
+    using list3 = mp_transform<mp_fill, list1, list2>;
 
-template<class R, class...Is, class... Ks, class Tp>
-R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
-{
-    return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
-}
+    using inner = mp_apply<mp_append, list3>;
 
-template<class T> using remove_cv_ref = typename std::remove_cv<
-    typename std::remove_reference<T>::type>::type;
+    // outer
 
-template<class T, class I> using tuple_element = typename std::tuple_element<I::value, T>::type;
-template<class T> using from_tuple_like = mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
+    using list4 = mp_transform<F, list1>;
 
-template<class... Tp,
-    class R = mp_append<std::tuple<>, from_tuple_like<remove_cv_ref<Tp>>...>>
-    R tuple_cat( Tp &&... tp )
-{
-    std::size_t const N = sizeof...(Tp);
+    using outer = mp_apply<mp_append, list4>;
 
-    // inner
+    //
 
-    using list1 = mp_list<from_tuple_like<remove_cv_ref<Tp>>...>;
-    using list2 = mp_iota_c<N>;
+    return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) );
+}
+
+
+
+

This function, however, is not entirely correct, in that it doesn’t handle some cases properly. For example, +trying to concatenate tuples containing move-only elements such as unique_ptr fails:

+
+
+
+
std::tuple<std::unique_ptr<int>> t1;
+std::tuple<std::unique_ptr<float>> t2;
 
-    using list3 = mp_transform<mp_fill, list1, list2>;
+auto result = ::tuple_cat( std::move( t1 ), std::move( t2 ) );
+
+
+
+

Trying to concatenate const tuples fails:

+
+
+
+
std::tuple<int> const t1;
+std::tuple<float> const t2;
 
-    using inner = mp_apply<mp_append, list3>;
+auto result = ::tuple_cat( t1, t2 );
+
+
+
+

And finally, the standard tuple_cat is specified to work on arbitrary tuple-like types (that is, all types +that support tuple_size, tuple_element, and get), while our implementation only works with tuple and +pair. std::array, for example, fails:

+
+
+
+
std::array<int, 2> t1{ 1, 2 };
+std::array<float, 3> t2{ 3.0f, 4.0f, 5.0f };
 
-    // outer
+auto result = ::tuple_cat( t1, t2 );
+
+
+
+

Let’s fix these one by one. Support for move-only types is easy, if one knows where to look. The problem is +that Tp that we’re passing to the helper tuple_cat_ is (correctly) tuple<unique_ptr<int>&&, unique_ptr<float>&&>, +but std::get<0>(tp) still returns unique_ptr<int>&, because tp is an lvalue. This behavior is a bit +surprising, but consistent with how rvalue reference members are treated by the language.

+
+
+

Long story short, we need std::move(tp) in tuple_cat_ to make tp an rvalue:

+
+
+
+
template<class R, class...Is, class... Ks, class Tp>
+R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
+{
+    return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
+}
+
+
+
+

Next, const-qualified tuples. The issue here is that we’re stripping references from the input tuples, but not +const. As a result, we’re trying to manipulate types such as tuple<int> const with Mp11 algorithms, and these +types do not fit the list concept. We just need to strip qualifiers as well, by defining the useful remove_cv_ref +primitive that is inexplicably missing from the standard library:

+
+
+
+
template<class T> using remove_cv_ref = typename std::remove_cv<
+    typename std::remove_reference<T>::type>::type;
+
+
+
+

and then by using remove_cv_ref<Tp> in place of typename std::remove_reference<Tp>::type:

+
+
+
+
template<class... Tp,
+    class R = mp_append<std::tuple<>, remove_cv_ref<Tp>...>>
+    R tuple_cat( Tp &&... tp )
+{
+    std::size_t const N = sizeof...(Tp);
 
-    using list4 = mp_transform<F, list1>;
+    // inner
 
-    using outer = mp_apply<mp_append, list4>;
+    using list1 = mp_list<mp_rename<remove_cv_ref<Tp>, mp_list>...>;
 
-    //
+    // ...
+
+
+
+

Finally, tuple-like types. We’ve so far exploited the fact that std::pair and std::tuple are valid Mp11 lists, +but in general, arbitrary tuple-like types aren’t, so we need to convert them into such. For that, we’ll need to +define a metafunction from_tuple_like that will take an arbitrary tuple-like type and will return, in our case, +the corresponding mp_list.

+
+
+

Technically, a more principled approach would’ve been to return std::tuple, but here mp_list will prove more +convenient.

+
+
+

What we need is, given a tuple-like type Tp, to obtain mp_list<std::tuple_element<0, Tp>::type, std::tuple_element<1, Tp>::type, +…​, std::tuple_element<N-1, Tp>::type>, where N is tuple_size<Tp>::value. Here’s one way to do it:

+
+
+
+
template<class T, class I> using tuple_element =
+    typename std::tuple_element<I::value, T>::type;
 
-    return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) );
-}
-
-
-
- -

- C++17 has a standard variant type, called std::variant. - It also defines a function template std::visit - that can be used to apply a function to the contained value of one or more - variants. So for instance, - if the variant v1 contains 1, - and the variant v2 contains 2.0f, - std::visit(f, v1, v2) - will call f(1, 2.0f). -

-

- However, std::visit has one limitation: it cannot return - a result unless all possible applications of the function have the same return - type. If, for instance, v1 - and v2 are both of type - std::variant<short, int, float>, -

-
std::visit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
-
-

- will fail to compile because the result of x - + y - can be either int or float depending on what v1 - and v2 hold. -

-

- A type that can hold either int - or float already exists, called, - surprisingly enough, std::variant<int, - float>. - Let's write our own function template rvisit - that is the same as visit - but returns a variant: -

-
template<class F, class... V> auto rvisit( F&& f, V&&... v )
-{
-    using R = /*...*/;
-    return std::visit( [&]( auto&&... x ){ return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); }, std::forward<V>( v )... );
-}
-
-

- What this does is basically calls std::visit - to do the work, but instead of passing it f, - we pass a lambda that does the same as f - except it converts the result to a common type R. - R is supposed to be std::variant<...> where the ellipsis denotes the - return types of calling f - with all possible combinations of variant values. -

-

- We'll first define a helper quoted metafunction Qret<F> - that returns the result of the application of F - to arguments of type T...: -

-
template<class F> struct Qret
-{
-    template<class... T> using fn = decltype( std::declval<F>()( std::declval<T>()... ) );
-};
-
-

- (Unfortunately, we can't just define this metafunction inside rvisit; the language prohibits defining - template aliases inside functions.) -

-

- With Qret in hand, a variant of the possible return types is - just a matter of applying it over the possible combinations of the variant - values: -

-
using R = mp_product_q<Qret<F>, std::remove_reference_t<V>...>;
-
-

- Why does this work? mp_product<F, - L1<T1...>, L2<T2...>, ..., Ln<Tn...>> returns L1<F<U1, U2, ..., Un>, ...>, - where Ui traverse all possible - combinations of list values. Since in our case all Li - are std::variant, the result will also be std::variant. - (mp_product_q is the same - as mp_product, but for quoted - metafunctions such as our Qret<F>.) -

-

- One more step remains. Suppose that, as above, we're passing two variants - of type std::variant<short, int, float> - and F is []( - auto const& x, auto const& y ){ return x + y; }. This - will generate R of length - 9, one per each combination, but many of those elements will be the same, - either int or float, and we need to filter out the duplicates. - So, -

-
using R = mp_unique<mp_product<Qret<F>::template fn, std::remove_reference_t<V>...>>;
-
-

- and we're done: -

-
#include <boost/mp11.hpp>
-#include <boost/core/demangle.hpp>
-#include <variant>
-#include <type_traits>
-#include <typeinfo>
-#include <iostream>
+template<class T> using from_tuple_like =
+    mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
+
+
+
+

(mp_iota<N> is an algorithm that returns an mp_list with elements mp_size_t<0>, mp_size_t<1>, …​, mp_size_t<N-1>.)

+
+
+

Remember that mp_product<F, L1, L2> performs the equivalent of two nested loops over the elements of L1 and L2, +applying F to the two variables and gathering the result. In our case L1 consists of the single element T, so +only the second loop (over mp_iota<N>, where N is tuple_size<T>), remains, and we get a list of the same type +as L1 (an mp_list) with contents tuple_element<T, mp_size_t<0>>, tuple_element<T, mp_size_t<1>>, …​, +tuple_element<T, mp_size_t<N-1>>.

+
+
+

For completeness’s sake, here’s another, more traditional way to achieve the same result:

+
+
+
+
template<class T> using from_tuple_like =
+    mp_transform_q<mp_bind_front<tuple_element, T>, mp_iota<std::tuple_size<T>>>;
+
+
+
+

With all these fixes applied, our fully operational tuple_cat now looks like this:

+
+
+
+
template<class L> using F = mp_iota<mp_size<L>>;
 
-using namespace boost::mp11;
+template<class R, class...Is, class... Ks, class Tp>
+R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
+{
+    return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
+}
 
-template<class F> struct Qret
-{
-    template<class... T> using fn = decltype( std::declval<F>()( std::declval<T>()... ) );
-};
+template<class T> using remove_cv_ref = typename std::remove_cv<
+    typename std::remove_reference<T>::type>::type;
 
-template<class F, class... V> auto rvisit( F&& f, V&&... v )
-{
-    using R = mp_unique<mp_product_q<Qret<F>, std::remove_reference_t<V>...>>;
-    return std::visit( [&]( auto&&... x ){ return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); }, std::forward<V>( v )... );
-}
+template<class T, class I> using tuple_element =
+    typename std::tuple_element<I::value, T>::type;
 
-template<class T> std::string name()
-{
-    return boost::core::demangle( typeid(T).name() );
-}
+template<class T> using from_tuple_like =
+    mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
 
-int main()
-{
-    std::variant<signed char, unsigned char, signed short, unsigned short, int, unsigned> v1( 1 );
+template<class... Tp,
+    class R = mp_append<std::tuple<>, from_tuple_like<remove_cv_ref<Tp>>...>>
+    R tuple_cat( Tp &&... tp )
+{
+    std::size_t const N = sizeof...(Tp);
 
-    std::cout << "(" << name<decltype(v1)>() << ")v1: ";
-    std::visit( []( auto const& x ){ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v1 );
+    // inner
 
-    std::variant<int, float, double> v2( 2.0f );
+    using list1 = mp_list<from_tuple_like<remove_cv_ref<Tp>>...>;
+    using list2 = mp_iota_c<N>;
 
-    std::cout << "(" << name<decltype(v2)>() << ")v2: ";
-    std::visit( []( auto const& x ){ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v2 );
+    using list3 = mp_transform<mp_fill, list1, list2>;
 
-    auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
+    using inner = mp_apply<mp_append, list3>;
 
-    std::cout << "(" << name<decltype(v3)>() << ")v3: ";
-    std::visit( []( auto const& x ){ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v3 );
-}
-
-
-
-
- -

- The contents of the library are in namespace boost::mp11. -

-
- -

- For an Mp11 integral constant type T, - T::value is an integral constant in the C++ - sense. -

-
- -
template<bool B> using mp_bool = std::integral_constant<bool, B>;
-
-
-
- -
using mp_true = mp_bool<true>;
-
-
-
- -
using mp_false = mp_bool<false>;
-
-
-
- -
template<class T> using mp_to_bool = mp_bool<static_cast<bool>(T::value)>;
-
-
-
- -
template<class T> using mp_not = mp_bool< !T::value >;
-
-
-
- -
template<int I> using mp_int = std::integral_constant<int, I>;
-
-
-
- -
template<std::size_t N> using mp_size_t = std::integral_constant<std::size_t, N>;
-
-
-
-
- -
- -
template<class... T> struct mp_list {};
-
-

- mp_list is the standard - list type of Mp11, although the library is not restricted to it and can - operate on arbitrary class templates such as std::tuple - or std::variant. Even std::pair - can be used if the transformation does not alter the number of the elements - in the list. -

-
-
- -
template<class L> using mp_size = /*...*/;
-
-

- mp_size<L> - returns the number of elements in the list L, - as a mp_size_t. In other - words, mp_size<L<T...>> - is an alias for mp_size_t<sizeof...(T)>. -

-
using L1 = mp_list<>;
-using R1 = mp_size<L1>; // mp_size_t<0>
+    // outer
 
-using L2 = std::pair<int, int>;
-using R2 = mp_size<L2>; // mp_size_t<2>
+    using list4 = mp_transform<F, list1>;
 
-using L3 = std::tuple<float>;
-using R3 = mp_size<L3>; // mp_size_t<1>
-
-
-
- -
template<class L> using mp_empty = mp_bool<mp_size<L>::value == 0>;
-
-

- mp_empty<L> - is an alias for mp_true - if the list L is empty, - for mp_false otherwise. -

-
-
- -
template<class L> using mp_front = /*...*/;
-
-

- mp_front<L> - is the first element of the list L. - That is, mp_front<L<T1, T...>> - is an alias for T1. -

-
using L1 = std::pair<int, float>;
-using R1 = mp_front<L1>; // int
+    using outer = mp_apply<mp_append, list4>;
 
-using L2 = std::tuple<float, double, long double>;
-using R2 = mp_front<L2>; // float
+    //
 
-using L3 = mp_list<char[1], char[2], char[3], char[4]>;
-using R3 = mp_front<L3>; // char[1]
-
-
-
- -
template<class L> using mp_pop_front = /*...*/;
-
-

- mp_pop_front<L> - removes the first element of the list L. - That is, mp_pop_front<L<T1, T...>> - is an alias for L<T...>. -

-
using L1 = std::tuple<float, double, long double>;
-using R1 = mp_pop_front<L1>; // std::tuple<double, long double>
+    return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) );
+}
+
+
+
+
+

Computing Return Types

+
+

C++17 has a standard variant type, called std::variant. It also defines a function template +std::visit that can be used to apply a function to the contained value of one or more variants. +So for instance, if the variant v1 contains 1, and the variant v2 contains 2.0f, +std::visit(f, v1, v2) will call f(1, 2.0f).

+
+
+

However, std::visit has one limitation: it cannot return a result unless all +possible applications of the function have the same return type. If, for instance, v1 and v2 +are both of type std::variant<short, int, float>,

+
+
+
+
std::visit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
+
+
+
+

will fail to compile because the result of x + y can be either int or float depending on +what v1 and v2 hold.

+
+
+

A type that can hold either int or float already exists, called, surprisingly enough, std::variant<int, float>. +Let’s write our own function template rvisit that is the same as visit but returns a variant:

+
+
+
+
template<class F, class... V> auto rvisit( F&& f, V&&... v )
+{
+    using R = /*...*/;
 
-using L2 = mp_list<void>;
-using R2 = mp_pop_front<L2>; // mp_list<>
-
-
-
- -
template<class L> using mp_first = mp_front<L>;
-
-

- mp_first is another name - for mp_front. -

-
-
- -
template<class L> using mp_rest = mp_pop_front<L>;
-
-

- mp_rest is another name - for mp_pop_front. -

-
-
- -
template<class L> using mp_second = /*...*/;
-
-

- mp_second<L> - is the second element of the list L. - That is, mp_second<L<T1, T2, T...>> - is an alias for T2. -

-
using L1 = std::pair<int, float>;
-using R1 = mp_second<L1>; // float
+    return std::visit( [&]( auto&&... x )
+        { return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); },
+        std::forward<V>( v )... );
+}
+
+
+
+

What this does is basically calls std::visit to do the work, but instead of passing it f, we pass a lambda that does the same as f except +it converts the result to a common type R. R is supposed to be std::variant<…​> where the ellipsis denotes the return types of +calling f with all possible combinations of variant values.

+
+
+

We’ll first define a helper quoted metafunction Qret<F> that returns the result of the application of F to arguments of type T…​:

+
+
+
+
template<class F> struct Qret
+{
+    template<class... T> using fn = decltype( std::declval<F>()( std::declval<T>()... ) );
+};
+
+
+
+

(Unfortunately, we can’t just define this metafunction inside rvisit; the language prohibits defining template aliases inside functions.)

+
+
+

With Qret in hand, a variant of the possible return types is just a matter of applying it over the possible combinations of the variant values:

+
+
+
+
using R = mp_product_q<Qret<F>, std::remove_reference_t<V>...>;
+
+
+
+

Why does this work? mp_product<F, L1<T1…​>, L2<T2…​>, …​, Ln<Tn…​>> returns L1<F<U1, U2, …​, Un>, …​>, where Ui traverse all +possible combinations of list values. Since in our case all Li are std::variant, the result will also be std::variant. (mp_product_q is +the same as mp_product, but for quoted metafunctions such as our Qret<F>.)

+
+
+

One more step remains. Suppose that, as above, we’re passing two variants of type std::variant<short, int, float> and F is +[]( auto const& x, auto const& y ){ return x + y; }. This will generate R of length 9, one per each combination, but many of those +elements will be the same, either int or float, and we need to filter out the duplicates. So,

+
+
+
+
using R = mp_unique<mp_product_q<Qret<F>, std::remove_reference_t<V>...>>;
+
+
+
+

and we’re done:

+
+
+
+
#include <boost/mp11.hpp>
+#include <boost/core/demangle.hpp>
+#include <variant>
+#include <type_traits>
+#include <typeinfo>
+#include <iostream>
 
-using L2 = std::tuple<float, double, long double>;
-using R2 = mp_second<L2>; // double
+using namespace boost::mp11;
 
-using L3 = mp_list<char[1], char[2], char[3], char[4]>;
-using R3 = mp_second<L3>; // char[2]
-
-
-
- -
template<class L> using mp_third = /*...*/;
-
-

- mp_third<L> - is the third element of the list L. - That is, mp_third<L<T1, T2, T3, T...>> - is an alias for T3. -

-
using L1 = std::tuple<float, double, long double>;
-using R1 = mp_third<L1>; // long double
+template<class F> struct Qret
+{
+    template<class... T> using fn = decltype( std::declval<F>()( std::declval<T>()... ) );
+};
 
-using L2 = mp_list<char[1], char[2], char[3], char[4]>;
-using R2 = mp_third<L2>; // char[3]
-
-
-
- -
template<class L, class... T> using mp_push_front = /*...*/;
-
-

- mp_push_front<L, T...> inserts the elements T... - at the front of the list L. - That is, mp_push_front<L<U...>, T...> is an alias for L<T..., U...>. -

-
using L1 = std::tuple<double, long double>;
-using R1 = mp_push_front<L1, float>; // std::tuple<float, double, long double>
+template<class F, class... V> auto rvisit( F&& f, V&&... v )
+{
+    using R = mp_unique<mp_product_q<Qret<F>, std::remove_reference_t<V>...>>;
 
-using L2 = mp_list<void>;
-using R2 = mp_push_front<L2, char[1], char[2]>; // mp_list<char[1], char[2], void>
-
-
-
- -
template<class L, class... T> using mp_push_back = /*...*/;
-
-

- mp_push_back<L, T...> inserts the elements T... - at the back of the list L. - That is, mp_push_back<L<U...>, T...> - is an alias for L<U..., T...>. -

-
using L1 = std::tuple<double, long double>;
-using R1 = mp_push_back<L1, float>; // std::tuple<double, long double, float>
+    return std::visit( [&]( auto&&... x )
+        { return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); },
+        std::forward<V>( v )... );
+}
 
-using L2 = mp_list<void>;
-using R2 = mp_push_back<L2, char[1], char[2]>; // mp_list<void, char[1], char[2]>
-
-
-
- -
template<class L, template<class...> class Y> using mp_rename = /*...*/;
-
-

- mp_rename<L, Y> changes the type of the list L to Y. - That is, mp_rename<L<T...>, Y> - is an alias for Y<T...>. -

-
using L1 = std::pair<double, long double>;
-using R1 = mp_rename<L1, std::tuple>; // std::tuple<double, long double>
+template<class T> std::string name()
+{
+    return boost::core::demangle( typeid(T).name() );
+}
 
-using L2 = std::tuple<void>;
-using R2 = mp_rename<L2, mp_list>; // mp_list<void>
-
-
-
- -
template<template<class...> class F, class L> using mp_apply = mp_rename<L, F>;
-
-

- mp_apply<F, L> applies the metafunction F to the contents of the list L, that is, mp_apply<F, L<T...>> - is an alias for F<T...>. - (mp_apply is the same as - mp_rename with the arguments - reversed.) -

-
using L1 = std::pair<double, long double>;
-using R1 = mp_apply<std::is_same, L1>; // std::is_same<double, long double>
-
-
-
- -
template<class Q, class L> using mp_apply_q = mp_apply<Q::template fn, L>;
-
-

- Same as mp_apply, but takes - a quoted metafunction. -

-
using L1 = std::tuple<double, long double>;
-using L2 = mp_list<int, long>;
-using R1 = mp_apply_q<mp_bind_front<mp_push_back, L1>, L2>; // std::tuple<double, long double, int, long>
-
-
-
- -
template<class... L> using mp_append = /*...*/;
-
-

- mp_append<L...> - concatenates the lists in L... into a single list that has the same - type as the first list. mp_append<> is an alias for mp_list<>. mp_append<L1<T1...>, L2<T2...>, ..., - Ln<Tn...>> - is an alias for L1<T1..., T2..., ..., Tn...>. -

-
using L1 = std::tuple<double, long double>;
-using L2 = mp_list<int>;
-using L3 = std::pair<short, long>;
-using L4 = mp_list<>;
+int main()
+{
+    std::variant<signed char, unsigned char, signed short, unsigned short,
+        int, unsigned> v1( 1 );
 
-using R1 = mp_append<L1, L2, L3, L4>; // std::tuple<double, long double, int, short, long>
-
-
-
- -
template<class L, class T> using mp_replace_front = /*...*/;
-
-

- mp_replace_front<L, T> replaces the first element of the list - L with T. - That is, mp_replace_front<L<U1, U...>, - T> - is an alias for L<T, U...>. -

-
using L1 = std::pair<int, float>;
-using R1 = mp_replace_front<L1, void>; // std::pair<void, float>
+    std::cout << "(" << name<decltype(v1)>() << ")v1: ";
+    std::visit( []( auto const& x )
+        { std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v1 );
 
-using L2 = std::tuple<float, double, long double>;
-using R2 = mp_replace_front<L2, void>; // std::tuple<void, double, long double>
+    std::variant<int, float, double> v2( 2.0f );
 
-using L3 = mp_list<char[1], char[2], char[3], char[4]>;
-using R3 = mp_replace_front<L3, void>; // mp_list<void, char[2], char[3], char[4]>;
-
-
-
- -
template<class L, class T> using mp_replace_first = mp_replace_front<L, T>;
-
-

- mp_replace_first is another - name for mp_replace_front. -

-
-
- -
template<class L, class T> using mp_replace_second = /*...*/;
-
-

- mp_replace_second<L, T> replaces the second element of the - list L with T. That is, mp_replace_second<L<U1, U2, U...>, - T> - is an alias for L<U1, T, U...>. -

-
using L1 = std::pair<int, float>;
-using R1 = mp_replace_second<L1, void>; // std::pair<int, void>
+    std::cout << "(" << name<decltype(v2)>() << ")v2: ";
+    std::visit( []( auto const& x )
+        { std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v2 );
 
-using L2 = std::tuple<float, double, long double>;
-using R2 = mp_replace_second<L2, void>; // std::tuple<float, void, long double>
+    auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
 
-using L3 = mp_list<char[1], char[2], char[3], char[4]>;
-using R3 = mp_replace_second<L3, void>; // mp_list<char[1], void, char[3], char[4]>;
-
-
-
- -
template<class L, class T> using mp_replace_third = /*...*/;
-
-

- mp_replace_third<L, T> replaces the third element of the list - L with T. - That is, mp_replace_third<L<U1, U2, U3, U...>, - T> - is an alias for L<U1, U2, T, U...>. -

-
using L1 = std::tuple<float, double, long double>;
-using R1 = mp_replace_third<L1, void>; // std::tuple<float, double, void>
+    std::cout << "(" << name<decltype(v3)>() << ")v3: ";
+    std::visit( []( auto const& x )
+        { std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v3 );
+}
+
+
+
+
+
+
+

Reference

+
+
+

The contents of the library are in namespace boost::mp11.

+
+
+

Integral Constants, <boost/mp11/integral.hpp>

+
+

For an Mp11 integral constant type T, T::value is an integral constant in the C++ sense.

+
+
+

mp_bool<B>

+
+
+
template<bool B> using mp_bool = std::integral_constant<bool, B>;
+
+
+
+
+

mp_true

+
+
+
using mp_true = mp_bool<true>;
+
+
+
+
+

mp_false

+
+
+
using mp_false = mp_bool<false>;
+
+
+
+
+

mp_to_bool<T>

+
+
+
template<class T> using mp_to_bool = mp_bool<static_cast<bool>(T::value)>;
+
+
+
+
+

mp_not<T>

+
+
+
template<class T> using mp_not = mp_bool< !T::value >;
+
+
+
+
+

mp_int<I>

+
+
+
template<int I> using mp_int = std::integral_constant<int, I>;
+
+
+
+
+

mp_size_t<N>

+
+
+
template<std::size_t N> using mp_size_t = std::integral_constant<std::size_t, N>;
+
+
+
+
+
+

List Operations, <boost/mp11/list.hpp>

+
+

mp_list<T…​>

+
+
+
template<class... T> struct mp_list {};
+
+
+
+

mp_list is the standard list type of Mp11, although the library is not restricted to it and can operate on arbitrary class templates +such as std::tuple or std::variant. Even std::pair can be used if the transformation does not alter the number of the elements in +the list.

+
+
+
+

mp_size<L>

+
+
+
template<class L> using mp_size = /*...*/;
+
+
+
+

mp_size<L> returns the number of elements in the list L, as a mp_size_t. In other words, mp_size<L<T…​>> is an alias for +mp_size_t<sizeof…​(T)>.

+
+
+
+
using L1 = mp_list<>;
+using R1 = mp_size<L1>; // mp_size_t<0>
+
+
+
+
+
using L2 = std::pair<int, int>;
+using R2 = mp_size<L2>; // mp_size_t<2>
+
+
+
+
+
using L3 = std::tuple<float>;
+using R3 = mp_size<L3>; // mp_size_t<1>
+
+
+
+
+

mp_empty<L>

+
+
+
template<class L> using mp_empty = mp_bool<mp_size<L>::value == 0>;
+
+
+
+

mp_empty<L> is an alias for mp_true if the list L is empty, for mp_false otherwise.

+
+
+
+

mp_front<L>

+
+
+
template<class L> using mp_front = /*...*/;
+
+
+
+

mp_front<L> is the first element of the list L. That is, mp_front<L<T1, T…​>> is an alias for T1.

+
+
+
+
using L1 = std::pair<int, float>;
+using R1 = mp_front<L1>; // int
+
+
+
+
+
using L2 = std::tuple<float, double, long double>;
+using R2 = mp_front<L2>; // float
+
+
+
+
+
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
+using R3 = mp_front<L3>; // char[1]
+
+
+
+
+

mp_pop_front<L>

+
+
+
template<class L> using mp_pop_front = /*...*/;
+
+
+
+

mp_pop_front<L> removes the first element of the list L. That is, mp_pop_front<L<T1, T…​>> is an alias for L<T…​>.

+
+
+
+
using L1 = std::tuple<float, double, long double>;
+using R1 = mp_pop_front<L1>; // std::tuple<double, long double>
+
+
+
+
+
using L2 = mp_list<void>;
+using R2 = mp_pop_front<L2>; // mp_list<>
+
+
+
+
+

mp_first<L>

+
+
+
template<class L> using mp_first = mp_front<L>;
+
+
+
+

mp_first is another name for mp_front.

+
+
+
+

mp_rest<L>

+
+
+
template<class L> using mp_rest = mp_pop_front<L>;
+
+
+
+

mp_rest is another name for mp_pop_front.

+
+
+
+

mp_second<L>

+
+
+
template<class L> using mp_second = /*...*/;
+
+
+
+

mp_second<L> is the second element of the list L. That is, mp_second<L<T1, T2, T…​>> is an alias for T2.

+
+
+
+
using L1 = std::pair<int, float>;
+using R1 = mp_second<L1>; // float
+
+
+
+
+
using L2 = std::tuple<float, double, long double>;
+using R2 = mp_second<L2>; // double
+
+
+
+
+
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
+using R3 = mp_second<L3>; // char[2]
+
+
+
+
+

mp_third<L>

+
+
+
template<class L> using mp_third = /*...*/;
+
+
+
+

mp_third<L> is the third element of the list L. That is, mp_third<L<T1, T2, T3, T…​>> is an alias for T3.

+
+
+
+
using L1 = std::tuple<float, double, long double>;
+using R1 = mp_third<L1>; // long double
+
+
+
+
+
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
+using R2 = mp_third<L2>; // char[3]
+
+
+
+
+

mp_push_front<L, T…​>

+
+
+
template<class L, class... T> using mp_push_front = /*...*/;
+
+
+
+

mp_push_front<L, T…​> inserts the elements T…​ at the front of the list L. That is, mp_push_front<L<U…​>, T…​> +is an alias for L<T…​, U…​>.

+
+
+
+
using L1 = std::tuple<double, long double>;
+using R1 = mp_push_front<L1, float>; // std::tuple<float, double, long double>
+
+
+
+
+
using L2 = mp_list<void>;
+using R2 = mp_push_front<L2, char[1], char[2]>; // mp_list<char[1], char[2], void>
+
+
+
+
+

mp_push_back<L, T…​>

+
+
+
template<class L, class... T> using mp_push_back = /*...*/;
+
+
+
+

mp_push_back<L, T…​> inserts the elements T…​ at the back of the list L. That is, mp_push_back<L<U…​>, T…​> +is an alias for L<U…​, T…​>.

+
+
+
+
using L1 = std::tuple<double, long double>;
+using R1 = mp_push_back<L1, float>; // std::tuple<double, long double, float>
+
+
+
+
+
using L2 = mp_list<void>;
+using R2 = mp_push_back<L2, char[1], char[2]>; // mp_list<void, char[1], char[2]>
+
+
+
+
+

mp_rename<L, Y>

+
+
+
template<class L, template<class...> class Y> using mp_rename = /*...*/;
+
+
+
+

mp_rename<L, Y> changes the type of the list L to Y. That is, mp_rename<L<T…​>, Y> is an alias for Y<T…​>.

+
+
+
+
using L1 = std::pair<double, long double>;
+using R1 = mp_rename<L1, std::tuple>; // std::tuple<double, long double>
+
+
+
+
+
using L2 = std::tuple<void>;
+using R2 = mp_rename<L2, mp_list>; // mp_list<void>
+
+
+
+
+

mp_apply<F, L>

+
+
+
template<template<class...> class F, class L> using mp_apply = mp_rename<L, F>;
+
+
+
+

mp_apply<F, L> applies the metafunction F to the contents of the list L, that is, mp_apply<F, L<T…​>> is an alias for F<T…​>. +(mp_apply is the same as mp_rename with the arguments reversed.)

+
+
+
+
using L1 = std::pair<double, long double>;
+using R1 = mp_apply<std::is_same, L1>; // std::is_same<double, long double>
+
+
+
+
+

mp_apply_q<Q, L>

+
+
+
template<class Q, class L> using mp_apply_q = mp_apply<Q::template fn, L>;
+
+
+
+

Same as mp_apply, but takes a quoted metafunction.

+
+
+
+
using L1 = std::tuple<double, long double>;
+using L2 = mp_list<int, long>;
 
-using L2 = mp_list<char[1], char[2], char[3], char[4]>;
-using R2 = mp_replace_third<L2, void>; // mp_list<char[1], char[2], void, char[4]>;
-
-
-
-
- -
- -
template<class T> struct mp_identity
-{
-    using type = T;
-};
-
-
-
- -
template<class T> using mp_identity_t = T;
-
-
-
- -
template<class... T> struct mp_inherit: T... {};
-
-
-
- -
template<bool C, class T, class... E> using mp_if_c = /*...*/;
-
-

- mp_if_c<true, T, E...> - is an alias for T. mp_if_c<false, T, E> is an alias for E. - Otherwise, the result is a substitution failure. -

-
using R1 = mp_if_c<true, int, void>;  // int
-using R2 = mp_if_c<flase, int, void>; // void
+using R1 = mp_apply_q<mp_bind_front<mp_push_back, L1>, L2>;
+// R1 is std::tuple<double, long double, int, long>
+
+
+
+
+

mp_append<L…​>

+
+
+
template<class... L> using mp_append = /*...*/;
+
+
+
+

mp_append<L…​> concatenates the lists in L…​ into a single list that has the same type as the first list. mp_append<> +is an alias for mp_list<>. mp_append<L1<T1…​>, L2<T2…​>, …​, Ln<Tn…​>> is an alias for L1<T1…​, T2…​, …​, Tn…​>.

+
+
+
+
using L1 = std::tuple<double, long double>;
+using L2 = mp_list<int>;
+using L3 = std::pair<short, long>;
+using L4 = mp_list<>;
 
-template<class I> using void_if_5 = mp_if_c<I::value == 5, void>; // `void` when `I::value` is 5, substitution failure otherwise
-
-
-
- -
template<class C, class T, class E...> using mp_if = mp_if_c<static_cast<bool>(C::value), T, E...>;
-
-

- Like mp_if_c, but the first - argument is a type. -

-
-
- -
template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c = /*...*/;
-
-

- mp_eval_if_c<C, T, F, - U...> - is an alias for T when - C is true, - for F<U...> - otherwise. Its purpose is to avoid evaluating F<U...> when the condition is true as it may not be valid in this case. -

-
-
- -
template<class C, class T, template<class...> class F, class... U> using mp_eval_if = mp_eval_if_c<static_cast<bool>(C::value), T, F, U...>;
-
-

- Like mp_eval_if_c, but - the first argument is a type. -

-
-
- -
template<class C, class T, class Q, class... U> using mp_eval_if_q = mp_eval_if<C, T, Q::template fn, U...>;
-
-

- Like mp_eval_if, but takes - a quoted metafunction. -

-
-
- -
template<template<class...> class F, class... T> using mp_valid = /*...*/;
-
-

- mp_valid<F, T...> is an alias for mp_true - when F<T...> - is a valid expression, for mp_false - otherwise. -

-
-
- -
template<template<class...> class F, class... T> using mp_defer = /*...*/;
-
-

- When mp_valid<F, T...> is mp_true, - mp_defer<F, T...> is a struct with a nested type - type which is an alias - for F<T...>. - Otherwise, mp_defer<F, T...> is an empty struct. -

-
-
- -
template<template<class...> class F> struct mp_quote
-{
-    template<class... T> using fn = F<T...>;
-};
-
-

- mp_quote<F> - transforms the template F - into a type with a nested template fn - such that fn<T...> - returns F<T...>. -

-
-
- -
template<class Q, class... T> using mp_invoke = typename Q::template fn<T...>;
-
-

- mp_invoke<Q, T...> evaluates the nested template fn of a quoted metafunction. mp_invoke<mp_quote<F>, T...> - returns F<T...>. -

-
-
-
- -
- -
template<class L1, class L2> using mp_assign = /*...*/;
-
-

- mp_assign<L1<T1...>, - L2<T2...>> - is an alias for L1<T2...>. - That is, it replaces the elements of L1 - with those of L2. -

-
-
- -
template<class L> using mp_clear = mp_assign<L, mp_list<>>;
-
-

- mp_clear<L<T...>> - is an alias for L<>, - that is, it removes the elements of L. -

-
-
- -
template<template<class...> class F, class... L> using mp_transform = /*...*/;
-
-

- mp_transform<F, L1<T1...>, L2<T2...>, ..., - Ln<Tn...>> - applies F to each successive - tuple of elements and returns L1<F<T1, T2, ..., Tn>...>. -

-
-
- -
template<class Q, class... L> using mp_transform_q = mp_transform<Q::template fn, L...>;
-
-

- As mp_transform, but takes - a quoted metafunction. -

-
-
- -
template<template<class...> class P, template<class...> class F, class L...> using mp_transform_if = /*...*/;
-
-

- mp_transform_if<P, F, L1, L2, ..., Ln> - replaces the elements of the list L1 - for which mp_to_bool<P<T1, T2, ..., Tn>> is mp_true - with F<T1, T2, ..., Tn>, and returns the result, where Ti are the corresponding elements of - Li. -

-
-
- -
template<class Qp, class Qf, class... L> using mp_transform_if_q = mp_transform_if<Qp::template fn, Qf::template fn, L...>;
-
-

- As mp_transform_if, but - takes a quoted metafunction. -

-
-
- -
template<class L, class V> using mp_fill = /*...*/;
-
-

- mp_fill<L<T...>, V> - returns L<V, V, ..., V>, - with the result having the same size as the input. -

-
-
- -
template<class L, class V> using mp_count = /*...*/;
-
-

- mp_count<L, V> returns mp_size_t<N>, where N - is the number of elements of L - same as V. -

-
-
- -
template<class L, template<class...> class P> using mp_count_if = /*...*/;
-
-

- mp_count_if<L, P> returns mp_size_t<N>, where N - is the number of elements T - of L for which mp_to_bool<P<T>> - is mp_true. -

-
-
- -
template<class L, class V> using mp_contains = mp_to_bool<mp_count<L, V>>;
-
-

- mp_contains<L, V> is mp_true - when L contains an element - V, mp_false - otherwise. -

-
-
- -
template<class L, std::size_t N> using mp_repeat_c = /*...*/;
-
-

- mp_repeat_c<L, N> returns a list of the same type as - L that consists of N concatenated copies of L. -

-
-
- -
template<class L, class N> using mp_repeat = /*...*/;
-
-

- Same as mp_repeat_c but - with a type argument N. - The number of copies is N::value - and must be nonnegative. -

-
-
- -
template<template<class...> class F, class... L> using mp_product = /*...*/;
-
-

- mp_product<F, L1<T1...>, L2<T2...>, ..., - Ln<Tn...>> - evaluates F<U1, U2, ..., Un> for values Ui - taken from the Cartesian product of the lists, as if the elements Ui are formed by n - nested loops, each traversing Li. - It returns a list of type L1 - containing the results of the application of F. -

-
-
- -
template<class Q, class... L> using mp_product_q = mp_product<Q::template fn, L...>;
-
-

- As mp_product, but takes - a quoted metafunction. -

-
-
- -
template<class L, std::size_t N> using mp_drop_c = /*...*/;
-
-

- mp_drop_c<L, N> removes the first N - elements of L and returns - the result. -

-
-
- -
template<class L, class N> using mp_drop = /*...*/;
-
-

- Same as mp_drop_c, but - with a type argument N. - N::value must be a nonnegative number. -

-
-
- -
template<std::size_t N> using mp_iota_c = /*...*/;
-
-

- mp_iota_c<N> - is an alias for mp_list<mp_size_t<0>, - mp_size_t<1>, ..., - mp_size_t<N-1>>. -

-
-
- -
template<class N> using mp_iota = /*...*/;
-
-

- Same as mp_iota_c, but - with a type argument N. - N::value must be a nonnegative number. Returns - mp_list<std::integral_constant<T, 0>, std::integral_constant<T, 1>, - ..., std::integral_constant<T, N::value-1>> - where T is the type of - N::value. -

-
-
- -
template<class L, std::size_t I> using mp_at_c = /*...*/;
-
-

- mp_at_c<L, I> returns the Ith - element of L, zero-based. -

-
-
- -
template<class L, class I> using mp_at = /*...*/;
-
-

- Same as mp_at_c, but with - a type argument I. I::value - must be a nonnegative number. -

-
-
- -
template<class L, std::size_t N> using mp_take_c = /*...*/;
-
-

- mp_take_c<L, N> returns a list of the same type as - L containing the first - N elements of L. -

-
-
- -
template<class L, class N> using mp_take = /*...*/;
-
-

- Same as mp_take_c, but - with a type argument N. - N::value must be a nonnegative number. -

-
-
- -
template<class L, std::size_t I, class... T> using mp_insert_c = mp_append<mp_take_c<L, I>, mp_push_front<mp_drop_c<L, I>, T...>>;
-
-

- Inserts the elements T... into the list L - at position I (a zero-based - index). -

-
-
- -
template<class L, class I, class... T> using mp_insert = mp_append<mp_take<L, I>, mp_push_front<mp_drop<L, I>, T...>>;
-
-

- Same as mp_insert_c, but - with a type argument I. -

-
-
- -
template<class L, std::size_t I, std::size_t J> using mp_erase = mp_append<mp_take_c<L, I>, mp_drop_c<L, J>>;
-
-

- Removes from the list L - the elements with indices from I - (inclusive) to J (exclusive). -

-
-
- -
template<class L, class I, class J> using mp_erase = mp_append<mp_take<L, I>, mp_drop<L, J>>;
-
-

- Same as mp_erase_c, but - with a type arguments I - and J. -

-
-
- -
template<class L, class V, class W> using mp_replace = /*...*/;
-
-

- Replaces all V elements - of L with W and returns the result. -

-
-
- -
template<class L, template<class...> class P, class W> using mp_replace_if = /*...*/;
-
-

- Replaces all T elements - of L for which mp_to_bool<P<T>> - is mp_true with W and returns the result. -

-
-
- -
template<class L, std::size_t I, class W> using mp_replace_at_c = /*...*/;
-
-

- Replaces the element of L - at zero-based index I with - W and returns the result. -

-
-
- -
template<class L, class I, class W> using mp_replace_at = /*...*/;
-
-

- Same as mp_replace_at_c, - but with a type argument I. - I::value must be a nonnegative number. -

-
-
- -
template<class L, template<class...> class P> using mp_copy_if = /*...*/;
-
-

- Copies the elements T of - L for which mp_to_bool<P<T>> - is mp_true to a new list - of the same type and returns it. -

-
-
- -
template<class L, class V> using mp_remove = /*...*/;
-
-

- Removes all V elements - of L and returns the result. -

-
-
- -
template<class L, template<class...> class P> using mp_remove_if = /*...*/;
-
-

- Removes all elements T - of L for which mp_to_bool<P<T>> - is mp_true and returns - the result. -

-
-
- -
template<class L, template<class...> class P> using mp_partition = /*...*/;
-
-

- mp_partition<L<T...>, P> - partitions L into two lists - L<U1...> - and L<U2...> - such that mp_to_bool<P<T>> - is mp_true for the elements - of L<U1...> - and mp_false for the elements - of L<U2...>. - Returns L<L<U1...>, - L<U2...>>. -

-
-
- -
template<class L, template<class...> class P> using mp_sort = /*...*/;
-
-

- mp_sort<L, P> sorts the list L - according to the strict weak ordering mp_to_bool<P<T, U>>. -

-
-
- -
template<class L, class V> using mp_find = /*...*/;
-
-

- mp_find<L, V> returns the index at which the type - V is located in the list - L. It's an alias for mp_size_t<I>, - where I is the zero-based - index of the first occurence of V - in L. If L does not contain V, - mp_find<L, V> is mp_size<L>. -

-
-
- -
template<class L, template<class...> class P> using mp_find_if = /*...*/;
-
-

- mp_find_f<L, P> is an alias for mp_size_t<I>, where I - is the zero-based index of the first element T - in L for which mp_to_bool<P<T>> - is mp_true. If there is - no such element, mp_find_if<L, P> - is mp_size<L>. -

-
-
- -
template<class L> using mp_reverse = /*...*/;
-
-

- mp_reverse<L<T1, T2, ..., Tn>> is L<Tn, ..., T2, T1>. -

-
-
- -
template<class L, class V, template<class...> class F> using mp_fold = /*...*/;
-
-

- mp_fold<L<T1, T2, ..., Tn>, V, F> - is F< - F< - F< - F<V, T1>, T2>, ...>, - Tn>, - or V, if L is empty. -

-
-
- -
template<class L, class V, template<class...> class F> using mp_reverse_fold = /*...*/;
-
-

- mp_reverse_fold<L<T1, T2, ..., Tn>, V, F> - is F<T1, F<T2, F<..., F<Tn, V>>>>, - or V, if L is empty. -

-
-
- -
template<class L> using mp_unique = /*...*/;
-
-

- mp_unique<L> - returns a list of the same type as L - with the duplicate elements removed. -

-
-
- -
template<class L, template<class...> class P> using mp_all_of = mp_bool< mp_count_if<L, P>::value == mp_size<L>::value >;
-
-

- mp_all_of<L, P> is mp_true - when P holds for all elements - of L, mp_false - otherwise. When L is empty, - the result is mp_true. -

-
-
- -
template<class L, template<class...> class P> using mp_none_of = mp_bool< mp_count_if<L, P>::value == 0 >;
-
-

- mp_none_of<L, P> is mp_true - when P holds for no element - of L, mp_false - otherwise. When L is empty, - the result is mp_true. -

-
-
- -
template<class L, template<class...> class P> using mp_any_of = mp_bool< mp_count_if<L, P>::value != 0 >;
-
-

- mp_any_of<L, P> is mp_true - when P holds for at least - one element of L, mp_false otherwise. When L is empty, the result is mp_false. -

-
-
- -
template<class L, class F> constexpr F mp_for_each(F&& f);
-
-

- mp_for_each<L>(f) calls - f with T() for each element T - of the list L, in order. -

-

- Returns std::forward<F>(f). -

-
-
- -
template<std::size_t N, class F> decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) mp_with_index( std::size_t i, F && f );
-
-

- mp_with_index<N>(i, f) calls f - with mp_size_t<i>() - and returns the result. i - must be less than N. -

-
template<class N, class F> decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) mp_with_index( std::size_t i, F && f );
-
-

- Returns mp_with_index<N::value>(i, f). -

-
-
-
- -

- A set is a list whose elements are unique. -

-
- -
template<class S, class V> using mp_set_contains = /*...*/;
-
-

- mp_set_contains<S, V> is mp_true - if the type V is an element - of the set S, mp_false otherwise. -

-
-
- -
template<class S, class... T> using mp_set_push_back = /*...*/;
-
-

- For each T1 in T..., - mp_set_push_back<S, T...> appends T1 - to the end of S if it's - not already an element of S. -

-
-
- -
template<class S, class... T> using mp_set_push_front = /*...*/;
-
-

- mp_set_push_front<S, T...> inserts at the front of S those elements of T... for which S - does not already contain the same type. -

-
-
-
- -

- A map is a list of lists, the inner lists having at least one element (the - key.) The keys of the map must be unique. -

-
- -
template<class M, class K> using mp_map_find = /*...*/;
-
-

- mp_map_find<M, K> is an alias for the element of the - map M with a key K, or for void, - if there is no such element. -

-
-
- -
template<class M, class K> using mp_map_contains = mp_not<std::is_same<mp_map_find<M, K>, void>>;
-
-

- mp_map_contains<M, K> is mp_true - if the map M contains an - element with a key K, - mp_false otherwise. -

-
-
- -
template<class M, class T> using mp_map_insert = mp_if< mp_map_contains<M, mp_first<T>>, M, mp_push_back<M, T> >;
-
-

- Inserts the element T into - the map M, if an element - with a key mp_first<T> - is not already in M. -

-
-
- -
template<class M, class T> using mp_map_replace = /*...*/;
-
-

- If the map M does not contain - an element with a key mp_first<T>, inserts it (using mp_push_back<M, T>); - otherwise, replaces the existing element with T. -

-
-
- -
template<class M, class T, template<class...> class F> using mp_map_update = /*...*/;
-
-

- If the map M does not contain - an element with a key mp_first<T>, inserts it (using mp_push_back<M, T>); - otherwise, replaces the existing element L<X, Y...> - with L<X, F<X, Y...>>. -

-
-
- -
template<class M, class K> using mp_map_erase = /*...*/;
-
-

- If the map M contains an - element with a key K, removes - it. -

-
-
-
- -
- -
template<class... T> using mp_void = void;
-
-

- Same as std::void_t from C++17. -

-
-
- -
template<class... T> using mp_and = /*...*/;
-
-

- mp_and<T...> - applies mp_to_bool to the - types in T..., - in order. If the result of an application is mp_false, - mp_and returns mp_false. If the application causes a - substitution failure, returns mp_false. - If all results are mp_true, - returns mp_true. mp_and<> - is mp_true. -

-
using R1 = mp_and<mp_true, mp_true>;   // mp_true
-using R2 = mp_and<mp_false, void>;     // mp_false, void is not reached
-using R3 = mp_and<mp_false, mp_false>; // mp_false
-using R4 = mp_and<void, mp_true>;      // mp_false (!)
-
-
-
- -
template<class... T> using mp_all = /*...*/;
-
-

- mp_all<T...> - is mp_true if mp_to_bool<U> - is mp_true for all types - U in T..., mp_false - otherwise. Same as mp_and, - but does not perform short-circuit evaluation. mp_and<mp_false, void> - is mp_false, but mp_all<mp_false, void> - is an error because void does - not have a nested value. - The upside is that mp_all - is potentially faster and does not mask substitution failures as mp_and does. -

-
using R1 = mp_and<mp_true, mp_true>;   // mp_true
-using R2 = mp_and<mp_false, void>;     // compile-time error
-using R3 = mp_and<mp_false, mp_false>; // mp_false
-using R4 = mp_and<void, mp_true>;      // compile-time error
-
-
-
- -
template<class... T> using mp_or = /*...*/;
-
-

- mp_or<T...> - applies mp_to_bool to the - types in T..., - in order. If the result of an application is mp_true, - mp_or returns mp_true. If all results are mp_false, returns mp_false. - mp_or<> - is mp_false. -

-
using R1 = mp_or<mp_true, mp_false>;   // mp_true
-using R2 = mp_or<mp_true, void>;       // mp_true, void is not reached
-using R3 = mp_or<mp_false, mp_false>;  // mp_false
-using R4 = mp_or<void, mp_true>;       // compile-time error
-
-
-
- -
template<class... T> using mp_any = /*...*/;
-
-

- mp_any<T...> - is mp_true if mp_to_bool<U> - is mp_true for any type - U in T..., mp_false - otherwise. Same as mp_or, - but does not perform short-circuit evaluation. -

-
using R1 = mp_any<mp_true, mp_false>;  // mp_true
-using R2 = mp_any<mp_true, void>;      // compile-time error
-using R3 = mp_any<mp_false, mp_false>; // mp_false
-using R4 = mp_any<void, mp_true>;      // compile-time error
-
-
-
- -
template<class... T> using mp_same = /*...*/;
-
-

- mp_same<T...> - is mp_true if all the types - in T... - are the same type, mp_false - otherwise. mp_same<> - is mp_true. -

-
-
- -
template<class... T> using mp_plus = /*...*/;
-
-

- mp_plus<T...> - is an integral constant type with a value that is the sum of U::value - for all types U in T.... - mp_plus<> - is mp_int<0>. -

-
-
-
- -
- -
template<std::size_t I> struct mp_arg;
-
-

- mp_arg<I> - is a quoted metafunction whose nested template fn<T...> returns the I-th - zero-based element of T.... -

-
-
- -
using _1 = mp_arg<0>;
-using _2 = mp_arg<1>;
-using _3 = mp_arg<2>;
-using _4 = mp_arg<3>;
-using _5 = mp_arg<4>;
-using _6 = mp_arg<5>;
-using _7 = mp_arg<6>;
-using _8 = mp_arg<7>;
-using _9 = mp_arg<8>;
-
-

- _1 to _9 - are placeholder types, the equivalent to the placeholders of boost::bind. -

-
-
- -
template<template<class...> class F, class... T> struct mp_bind;
-
-

- mp_bind<F, T...> is a quoted metafunction that implements - the type-based equivalent of boost::bind. - Its nested template fn<U...> returns F<V...>, where V... is T... with the placeholders replaced by the - corresponding element of U... and the mp_bind - expressions replaced with their corresponding evaluations against U.... -

-

- For example, mp_bind<F, int, _2, mp_bind<G, _1>>::fn<float, void> - is F<int, void, G<float>>. -

-
-
- -
template<class Q, class... T> using mp_bind_q = mp_bind<Q::template fn, T...>;
-
-

- As mp_bind, but takes a - quoted metafunction. -

-
-
- -
template<template<class...> class F, class... T> struct mp_bind_front;
-
-

- mp_bind_front<F, T...> binds the leftmost arguments of - F to T.... Its nested template fn<U...> returns F<T..., U...>. -

-
-
- -
template<class Q, class... T> using mp_bind_front_q = mp_bind_front<Q::template fn, T...>;
-
-

- As mp_bind_front, but takes - a quoted metafunction. -

-
-
- -
template<template<class...> class F, class... T> struct mp_bind_back;
-
-

- mp_bind_back<F, T...> binds the rightmost arguments of - F to T.... Its nested template fn<U...> returns F<U..., T...>. -

-
-
- -
template<class Q, class... T> using mp_bind_back_q = mp_bind_back<Q::template fn, T...>;
-
-

- As mp_bind_back, but takes - a quoted metafunction. -

-
-
-
- -
- -
template<class T, T... I> struct integer_sequence
-{
-};
-
-

- integer_sequence<T, I...> holds a sequence of integers of - type T. Same as C++14's - std::integer_sequence. -

-
-
- -
template<class T, T N> using make_integer_sequence = /*...*/;
-
-

- make_integer_sequence<T, N> is integer_sequence<T, 0, - 1, ..., N-1>. - Same as C++14's std::make_integer_sequence. -

-
-
- -
template<std::size_t... I> using index_sequence = integer_sequence<std::size_t, I...>;
-
-

- index_sequence<I...> - is an alias for integer_sequence<size_t, I...>. - Same as C++14's std::index_sequence. -

-
-
- -
template<std::size_t N> using make_index_sequence = make_integer_sequence<std::size_t, N>;
-
-

- make_index_sequence<N> - is index_sequence<0, 1, ..., N-1>. Same as C++14's std::make_index_sequence. -

-
-
- -
template<class... T> using index_sequence_for = make_integer_sequence<std::size_t, sizeof...(T)>;
-
-

- index_sequence_for<N> - is make_index_sequence<sizeof...(T)>. Same as C++14's std::index_sequence_for. -

-
-
-
- -
- -
template<class Tp, class F> constexpr F tuple_for_each(Tp&& tp, F&& f);
-
-

- tuple_for_each(tp, f) applies - the function object f to - each element of tp by evaluating - the expression f(std::get<J>(std::forward<Tp>(tp))) - for J in 0..N-1, - where N is std::tuple_size<typename std::remove_reference<Tp>::type>::value. -

-

- Returns std::forward<F>(f). -

-
-
-
-
- - - -

Last revised: June 04, 2017 at 10:41:56 GMT

-
-
+using R1 = mp_append<L1, L2, L3, L4>; // std::tuple<double, long double, int, short, long>
+
+
+
+
+

mp_replace_front<L, T>

+
+
+
template<class L, class T> using mp_replace_front = /*...*/;
+
+
+
+

mp_replace_front<L, T> replaces the first element of the list L with T. That is, mp_replace_front<L<U1, U…​>, T> is +an alias for L<T, U…​>.

+
+
+
+
using L1 = std::pair<int, float>;
+using R1 = mp_replace_front<L1, void>; // std::pair<void, float>
+
+
+
+
+
using L2 = std::tuple<float, double, long double>;
+using R2 = mp_replace_front<L2, void>; // std::tuple<void, double, long double>
+
+
+
+
+
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
+using R3 = mp_replace_front<L3, void>; // mp_list<void, char[2], char[3], char[4]>;
+
+
+
+
+

mp_replace_first<L, T>

+
+
+
template<class L, class T> using mp_replace_first = mp_replace_front<L, T>;
+
+
+
+

mp_replace_first is another name for mp_replace_front.

+
+
+
+

mp_replace_second<L, T>

+
+
+
template<class L, class T> using mp_replace_second = /*...*/;
+
+
+
+

mp_replace_second<L, T> replaces the second element of the list L with T. That is, mp_replace_second<L<U1, U2, U…​>, T> +is an alias for L<U1, T, U…​>.

+
+
+
+
using L1 = std::pair<int, float>;
+using R1 = mp_replace_second<L1, void>; // std::pair<int, void>
+
+
+
+
+
using L2 = std::tuple<float, double, long double>;
+using R2 = mp_replace_second<L2, void>; // std::tuple<float, void, long double>
+
+
+
+
+
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
+using R3 = mp_replace_second<L3, void>; // mp_list<char[1], void, char[3], char[4]>;
+
+
+
+
+

mp_replace_third<L, T>

+
+
+
template<class L, class T> using mp_replace_third = /*...*/;
+
+
+
+

mp_replace_third<L, T> replaces the third element of the list L with T. That is, mp_replace_third<L<U1, U2, U3, U…​>, T> +is an alias for L<U1, U2, T, U…​>.

+
+
+
+
using L1 = std::tuple<float, double, long double>;
+using R1 = mp_replace_third<L1, void>; // std::tuple<float, double, void>
+
+
+
+
+
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
+using R2 = mp_replace_third<L2, void>; // mp_list<char[1], char[2], void, char[4]>;
+
+
+
+ +
+

Utility Components, <boost/mp11/utility.hpp>

+
+

mp_identity<T>

+
+
+
template<class T> struct mp_identity
+{
+    using type = T;
+};
+
+
+
+
+

mp_identity_t<T>

+
+
+
template<class T> using mp_identity_t = T;
+
+
+
+
+

mp_inherit<T…​>

+
+
+
template<class... T> struct mp_inherit: T... {};
+
+
+
+
+

mp_if_c<C, T, E…​>

+
+
+
template<bool C, class T, class... E> using mp_if_c = /*...*/;
+
+
+
+

mp_if_c<true, T, E…​> is an alias for T. mp_if_c<false, T, E> is an alias for E. Otherwise, the result is a substitution failure.

+
+
+
+
using R1 = mp_if_c<true, int, void>;  // int
+using R2 = mp_if_c<flase, int, void>; // void
+
+
+
+
+
template<class I> using void_if_5 = mp_if_c<I::value == 5, void>; // `void` when `I::value` is 5, substitution failure otherwise
+
+
+
+
+

mp_if<C, T, E…​>

+
+
+
template<class C, class T, class E...> using mp_if = mp_if_c<static_cast<bool>(C::value), T, E...>;
+
+
+
+

Like mp_if_c, but the first argument is a type.

+
+
+
+

mp_eval_if_c<C, T, F, U…​>

+
+
+
template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c = /*...*/;
+
+
+
+

mp_eval_if_c<C, T, F, U…​> is an alias for T when C is true, for F<U…​> otherwise. Its purpose +is to avoid evaluating F<U…​> when the condition is true as it may not be valid in this case.

+
+
+
+

mp_eval_if<C, T, F, U…​>

+
+
+
template<class C, class T, template<class...> class F, class... U> using mp_eval_if = mp_eval_if_c<static_cast<bool>(C::value), T, F, U...>;
+
+
+
+

Like mp_eval_if_c, but the first argument is a type.

+
+
+
+

mp_eval_if_q<C, T, Q, U…​>

+
+
+
template<class C, class T, class Q, class... U> using mp_eval_if_q = mp_eval_if<C, T, Q::template fn, U...>;
+
+
+
+

Like mp_eval_if, but takes a quoted metafunction.

+
+
+
+

mp_valid<F, T…​>

+
+
+
template<template<class...> class F, class... T> using mp_valid = /*...*/;
+
+
+
+

mp_valid<F, T…​> is an alias for mp_true when F<T…​> is a valid expression, for mp_false otherwise.

+
+
+
+

mp_defer<F, T…​>

+
+
+
template<template<class...> class F, class... T> using mp_defer = /*...*/;
+
+
+
+

When mp_valid<F, T…​> is mp_true, mp_defer<F, T…​> is a struct with a nested type type which is an alias for F<T…​>. Otherwise, +mp_defer<F, T…​> is an empty struct.

+
+
+
+

mp_quote<F>

+
+
+
template<template<class...> class F> struct mp_quote
+{
+    template<class... T> using fn = F<T...>;
+};
+
+
+
+

mp_quote<F> transforms the template F into a type with a nested template fn such that fn<T…​> returns F<T…​>.

+
+
+
+

mp_invoke<Q, T…​>

+
+
+
template<class Q, class... T> using mp_invoke = typename Q::template fn<T...>;
+
+
+
+

mp_invoke<Q, T…​> evaluates the nested template fn of a quoted metafunction. mp_invoke<mp_quote<F>, T…​> returns F<T…​>.

+
+
+
+
+

Algorithms, <boost/mp11/algorithm.hpp>

+
+

mp_assign<L1, L2>

+
+
+
template<class L1, class L2> using mp_assign = /*...*/;
+
+
+
+

mp_assign<L1<T1…​>, L2<T2…​>> is an alias for L1<T2…​>. That is, it replaces the elements of L1 with those of L2.

+
+
+
+

mp_clear<L>

+
+
+
template<class L> using mp_clear = mp_assign<L, mp_list<>>;
+
+
+
+

mp_clear<L<T…​>> is an alias for L<>, that is, it removes the elements of L.

+
+
+
+

mp_transform<F, L…​>

+
+
+
template<template<class...> class F, class... L> using mp_transform = /*...*/;
+
+
+
+

mp_transform<F, L1<T1…​>, L2<T2…​>, …​, Ln<Tn…​>> applies F to each successive tuple of elements and returns L1<F<T1, T2, …​, Tn>…​>.

+
+
+
+

mp_transform_q<Q, L…​>

+
+
+
template<class Q, class... L> using mp_transform_q = mp_transform<Q::template fn, L...>;
+
+
+
+

As mp_transform, but takes a quoted metafunction.

+
+
+
+

mp_transform_if<P, F, L…​>

+
+
+
template<template<class...> class P, template<class...> class F, class L...> using mp_transform_if = /*...*/;
+
+
+
+

mp_transform_if<P, F, L1, L2, …​, Ln> replaces the elements of the list L1 for which mp_to_bool<P<T1, T2, …​, Tn>> is mp_true with +F<T1, T2, …​, Tn>, and returns the result, where Ti are the corresponding elements of Li.

+
+
+
+

mp_transform_if_q<Qp, Qf, L…​>

+
+
+
template<class Qp, class Qf, class... L> using mp_transform_if_q = mp_transform_if<Qp::template fn, Qf::template fn, L...>;
+
+
+
+

As mp_transform_if, but takes a quoted metafunction.

+
+
+
+

mp_fill<L, V>

+
+
+
template<class L, class V> using mp_fill = /*...*/;
+
+
+
+

mp_fill<L<T…​>, V> returns L<V, V, …​, V>, with the result having the same size as the input.

+
+
+
+

mp_count<L, V>

+
+
+
template<class L, class V> using mp_count = /*...*/;
+
+
+
+

mp_count<L, V> returns mp_size_t<N>, where N is the number of elements of L same as V.

+
+
+
+

mp_count_if<L, P>

+
+
+
template<class L, template<class...> class P> using mp_count_if = /*...*/;
+
+
+
+

mp_count_if<L, P> returns mp_size_t<N>, where N is the number of elements T of L for which mp_to_bool<P<T>> is mp_true.

+
+
+
+

mp_contains<L, V>

+
+
+
template<class L, class V> using mp_contains = mp_to_bool<mp_count<L, V>>;
+
+
+
+

mp_contains<L, V> is mp_true when L contains an element V, mp_false otherwise.

+
+
+
+

mp_repeat_c<L, N>

+
+
+
template<class L, std::size_t N> using mp_repeat_c = /*...*/;
+
+
+
+

mp_repeat_c<L, N> returns a list of the same type as L that consists of N concatenated copies of L.

+
+
+
+

mp_repeat<L, N>

+
+
+
template<class L, class N> using mp_repeat = /*...*/;
+
+
+
+

Same as mp_repeat_c but with a type argument N. The number of copies is N::value and must be nonnegative.

+
+
+
+

mp_product<F, L…​>

+
+
+
template<template<class...> class F, class... L> using mp_product = /*...*/;
+
+
+
+

mp_product<F, L1<T1…​>, L2<T2…​>, …​, Ln<Tn…​>> evaluates F<U1, U2, …​, Un> for values Ui taken from +the Cartesian product of the lists, as if the elements Ui are formed by n nested loops, each traversing Li. +It returns a list of type L1 containing the results of the application of F.

+
+
+
+

mp_product_q<Q, L…​>

+
+
+
template<class Q, class... L> using mp_product_q = mp_product<Q::template fn, L...>;
+
+
+
+

As mp_product, but takes a quoted metafunction.

+
+
+
+

mp_drop_c<L, N>

+
+
+
template<class L, std::size_t N> using mp_drop_c = /*...*/;
+
+
+
+

mp_drop_c<L, N> removes the first N elements of L and returns the result.

+
+
+
+

mp_drop<L, N>

+
+
+
template<class L, class N> using mp_drop = /*...*/;
+
+
+
+

Same as mp_drop_c, but with a type argument N. N::value must be a nonnegative number.

+
+
+
+

mp_iota_c<N>

+
+
+
template<std::size_t N> using mp_iota_c = /*...*/;
+
+
+
+

mp_iota_c<N> is an alias for mp_list<mp_size_t<0>, mp_size_t<1>, …​, mp_size_t<N-1>>.

+
+
+
+

mp_iota<N>

+
+
+
template<class N> using mp_iota = /*...*/;
+
+
+
+

Same as mp_iota_c, but with a type argument N. N::value must be a nonnegative number. Returns +mp_list<std::integral_constant<T, 0>, std::integral_constant<T, 1>, …​, std::integral_constant<T, N::value-1>> +where T is the type of N::value.

+
+
+
+

mp_at_c<L, I>

+
+
+
template<class L, std::size_t I> using mp_at_c = /*...*/;
+
+
+
+

mp_at_c<L, I> returns the I`th element of `L, zero-based.

+
+
+
+

mp_at<L, I>

+
+
+
template<class L, class I> using mp_at = /*...*/;
+
+
+
+

Same as mp_at_c, but with a type argument I. I::value must be a nonnegative number.

+
+
+
+

mp_take_c<L, N>

+
+
+
template<class L, std::size_t N> using mp_take_c = /*...*/;
+
+
+
+

mp_take_c<L, N> returns a list of the same type as L containing the first N elements of L.

+
+
+
+

mp_take<L, N>

+
+
+
template<class L, class N> using mp_take = /*...*/;
+
+
+
+

Same as mp_take_c, but with a type argument N. N::value must be a nonnegative number.

+
+
+
+

mp_insert_c<L, I, T…​>

+
+
+
template<class L, std::size_t I, class... T> using mp_insert_c = mp_append<mp_take_c<L, I>, mp_push_front<mp_drop_c<L, I>, T...>>;
+
+
+
+

Inserts the elements T…​ into the list L at position I (a zero-based index).

+
+
+
+

mp_insert<L, I, T…​>

+
+
+
template<class L, class I, class... T> using mp_insert = mp_append<mp_take<L, I>, mp_push_front<mp_drop<L, I>, T...>>;
+
+
+
+

Same as mp_insert_c, but with a type argument I.

+
+
+
+

mp_erase_c<L, I, J>

+
+
+
template<class L, std::size_t I, std::size_t J> using mp_erase = mp_append<mp_take_c<L, I>, mp_drop_c<L, J>>;
+
+
+
+

Removes from the list L the elements with indices from I (inclusive) to J (exclusive).

+
+
+
+

mp_erase<L, I, J>

+
+
+
template<class L, class I, class J> using mp_erase = mp_append<mp_take<L, I>, mp_drop<L, J>>;
+
+
+
+

Same as mp_erase_c, but with a type arguments I and J.

+
+
+
+

mp_replace<L, V, W>

+
+
+
template<class L, class V, class W> using mp_replace = /*...*/;
+
+
+
+

Replaces all V elements of L with W and returns the result.

+
+
+
+

mp_replace_if<L, P, W>

+
+
+
template<class L, template<class...> class P, class W> using mp_replace_if = /*...*/;
+
+
+
+

Replaces all T elements of L for which mp_to_bool<P<T>> is mp_true with W and returns the result.

+
+
+
+

mp_replace_at_c<L, I, W>

+
+
+
template<class L, std::size_t I, class W> using mp_replace_at_c = /*...*/;
+
+
+
+

Replaces the element of L at zero-based index I with W and returns the result.

+
+
+
+

mp_replace_at<L, I, W>

+
+
+
template<class L, class I, class W> using mp_replace_at = /*...*/;
+
+
+
+

Same as mp_replace_at_c, but with a type argument I. I::value must be a nonnegative number.

+
+
+
+

mp_copy_if<L, P>

+
+
+
template<class L, template<class...> class P> using mp_copy_if = /*...*/;
+
+
+
+

Copies the elements T of L for which mp_to_bool<P<T>> is mp_true to a new list of the same type and returns it.

+
+
+
+

mp_remove<L, V>

+
+
+
template<class L, class V> using mp_remove = /*...*/;
+
+
+
+

Removes all V elements of L and returns the result.

+
+
+
+

mp_remove_if<L, P>

+
+
+
template<class L, template<class...> class P> using mp_remove_if = /*...*/;
+
+
+
+

Removes all elements T of L for which mp_to_bool<P<T>> is mp_true and returns the result.

+
+
+
+

mp_partition<L, P>

+
+
+
template<class L, template<class...> class P> using mp_partition = /*...*/;
+
+
+
+

mp_partition<L<T…​>, P> partitions L into two lists L<U1…​> and L<U2…​> such that mp_to_bool<P<T>> is mp_true +for the elements of L<U1…​> and mp_false for the elements of L<U2…​>. Returns L<L<U1…​>, L<U2…​>>.

+
+
+
+

mp_sort<L, P>

+
+
+
template<class L, template<class...> class P> using mp_sort = /*...*/;
+
+
+
+

mp_sort<L, P> sorts the list L according to the strict weak ordering mp_to_bool<P<T, U>>.

+
+
+
+

mp_find<L, V>

+
+
+
template<class L, class V> using mp_find = /*...*/;
+
+
+
+

mp_find<L, V> returns the index at which the type V is located in the list L. It’s an alias for mp_size_t<I>, +where I is the zero-based index of the first occurence of V in L. If L does not contain V, mp_find<L, V> +is mp_size<L>.

+
+
+
+

mp_find_if<L, P>

+
+
+
template<class L, template<class...> class P> using mp_find_if = /*...*/;
+
+
+
+

mp_find_f<L, P> is an alias for mp_size_t<I>, where I is the zero-based index of the first element T in L for which +mp_to_bool<P<T>> is mp_true. If there is no such element, mp_find_if<L, P> is mp_size<L>.

+
+
+
+

mp_reverse<L>

+
+
+
template<class L> using mp_reverse = /*...*/;
+
+
+
+

mp_reverse<L<T1, T2, …​, Tn>> is L<Tn, …​, T2, T1>.

+
+
+
+

mp_fold<L, V, F>

+
+
+
template<class L, class V, template<class...> class F> using mp_fold = /*...*/;
+
+
+
+

mp_fold<L<T1, T2, …​, Tn>, V, F> is F< F< F< F<V, T1>, T2>, …​>, Tn>, or V, if L is empty.

+
+
+
+

mp_reverse_fold<L, V, F>

+
+
+
template<class L, class V, template<class...> class F> using mp_reverse_fold = /*...*/;
+
+
+
+

mp_reverse_fold<L<T1, T2, …​, Tn>, V, F> is F<T1, F<T2, F<…​, F<Tn, V>>>>, or V, if L is empty.

+
+
+
+

mp_unique<L>

+
+
+
template<class L> using mp_unique = /*...*/;
+
+
+
+

mp_unique<L> returns a list of the same type as L with the duplicate elements removed.

+
+
+
+

mp_all_of<L, P>

+
+
+
template<class L, template<class...> class P> using mp_all_of = mp_bool< mp_count_if<L, P>::value == mp_size<L>::value >;
+
+
+
+

mp_all_of<L, P> is mp_true when P holds for all elements of L, mp_false otherwise. When L is empty, the result is mp_true.

+
+
+
+

mp_none_of<L, P>

+
+
+
template<class L, template<class...> class P> using mp_none_of = mp_bool< mp_count_if<L, P>::value == 0 >;
+
+
+
+

mp_none_of<L, P> is mp_true when P holds for no element of L, mp_false otherwise. When L is empty, the result is mp_true.

+
+
+
+

mp_any_of<L, P>

+
+
+
template<class L, template<class...> class P> using mp_any_of = mp_bool< mp_count_if<L, P>::value != 0 >;
+
+
+
+

mp_any_of<L, P> is mp_true when P holds for at least one element of L, mp_false otherwise. When L is empty, the result is mp_false.

+
+
+
+

mp_for_each<L>(f)

+
+
+
template<class L, class F> constexpr F mp_for_each(F&& f);
+
+
+
+

mp_for_each<L>(f) calls f with T() for each element T of the list L, in order.

+
+
+

Returns std::forward<F>(f).

+
+
+
+

mp_with_index<N>(i, f)

+
+
+
template<std::size_t N, class F> decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) mp_with_index( std::size_t i, F && f );
+
+
+
+

mp_with_index<N>(i, f) calls f with mp_size_t<i>() and returns the result. i must be less than N.

+
+
+
+
template<class N, class F> decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) mp_with_index( std::size_t i, F && f );
+
+
+
+

Returns mp_with_index<N::value>(i, f).

+
+
+
+
+

Set Operations, <boost/mp11/set.hpp>

+
+

A set is a list whose elements are unique.

+
+
+

mp_set_contains<S, V>

+
+
+
template<class S, class V> using mp_set_contains = /*...*/;
+
+
+
+

mp_set_contains<S, V> is mp_true if the type V is an element of the set S, mp_false otherwise.

+
+
+
+

mp_set_push_back<S, T…​>

+
+
+
template<class S, class... T> using mp_set_push_back = /*...*/;
+
+
+
+

For each T1 in T…​, mp_set_push_back<S, T…​> appends T1 to the end of S if it’s not already an element of S.

+
+
+
+

mp_set_push_front<S, T…​>

+
+
+
template<class S, class... T> using mp_set_push_front = /*...*/;
+
+
+
+

mp_set_push_front<S, T…​> inserts at the front of S those elements of T…​ for which S does not already contain the same type.

+
+
+
+
+

Map Operations, <boost/mp11/map.hpp>

+
+

A map is a list of lists, the inner lists having at least one element (the key.) The keys of the map must be unique.

+
+
+

mp_map_find<M, K>

+
+
+
template<class M, class K> using mp_map_find = /*...*/;
+
+
+
+

mp_map_find<M, K> is an alias for the element of the map M with a key K, or for void, if there is no such element.

+
+
+
+

mp_map_contains<M, K>

+
+
+
template<class M, class K> using mp_map_contains = mp_not<std::is_same<mp_map_find<M, K>, void>>;
+
+
+
+

mp_map_contains<M, K> is mp_true if the map M contains an element with a key K, mp_false otherwise.

+
+
+
+

mp_map_insert<M, T>

+
+
+
template<class M, class T> using mp_map_insert = mp_if< mp_map_contains<M, mp_first<T>>, M, mp_push_back<M, T> >;
+
+
+
+

Inserts the element T into the map M, if an element with a key mp_first<T> is not already in M.

+
+
+
+

mp_map_replace<M, T>

+
+
+
template<class M, class T> using mp_map_replace = /*...*/;
+
+
+
+

If the map M does not contain an element with a key mp_first<T>, inserts it (using mp_push_back<M, T>); otherwise, +replaces the existing element with T.

+
+
+
+

mp_map_update<M, T, F>

+
+
+
template<class M, class T, template<class...> class F> using mp_map_update = /*...*/;
+
+
+
+

If the map M does not contain an element with a key mp_first<T>, inserts it (using mp_push_back<M, T>); otherwise, +replaces the existing element L<X, Y…​> with L<X, F<X, Y…​>>.

+
+
+
+

mp_map_erase<M, K>

+
+
+
template<class M, class K> using mp_map_erase = /*...*/;
+
+
+
+

If the map M contains an element with a key K, removes it.

+
+
+
+
+

Helper Metafunctions, <boost/mp11/function.hpp>

+
+

mp_void<T…​>

+
+
+
template<class... T> using mp_void = void;
+
+
+
+

Same as std::void_t from C++17.

+
+
+
+

mp_and<T…​>

+
+
+
template<class... T> using mp_and = /*...*/;
+
+
+
+

mp_and<T…​> applies mp_to_bool to the types in T…​, in order. If the result of an application is mp_false, mp_and +returns mp_false. If the application causes a substitution failure, returns mp_false. If all results are mp_true, +returns mp_true. mp_and<> is mp_true.

+
+
+
+
using R1 = mp_and<mp_true, mp_true>;   // mp_true
+using R2 = mp_and<mp_false, void>;     // mp_false, void is not reached
+using R3 = mp_and<mp_false, mp_false>; // mp_false
+using R4 = mp_and<void, mp_true>;      // mp_false (!)
+
+
+
+
+

mp_all<T…​>

+
+
+
template<class... T> using mp_all = /*...*/;
+
+
+
+

mp_all<T…​> is mp_true if mp_to_bool<U> is mp_true for all types U in T…​, mp_false otherwise. Same as +mp_and, but does not perform short-circuit evaluation. mp_and<mp_false, void> is mp_false, but mp_all<mp_false, void> +is an error because void does not have a nested value. The upside is that mp_all is potentially faster and does not +mask substitution failures as mp_and does.

+
+
+
+
using R1 = mp_and<mp_true, mp_true>;   // mp_true
+using R2 = mp_and<mp_false, void>;     // compile-time error
+using R3 = mp_and<mp_false, mp_false>; // mp_false
+using R4 = mp_and<void, mp_true>;      // compile-time error
+
+
+
+
+

mp_or<T…​>

+
+
+
template<class... T> using mp_or = /*...*/;
+
+
+
+

mp_or<T…​> applies mp_to_bool to the types in T…​, in order. If the result of an application is mp_true, mp_or +returns mp_true. If all results are mp_false, returns mp_false. mp_or<> is mp_false.

+
+
+
+
using R1 = mp_or<mp_true, mp_false>;   // mp_true
+using R2 = mp_or<mp_true, void>;       // mp_true, void is not reached
+using R3 = mp_or<mp_false, mp_false>;  // mp_false
+using R4 = mp_or<void, mp_true>;       // compile-time error
+
+
+
+
+

mp_any<T…​>

+
+
+
template<class... T> using mp_any = /*...*/;
+
+
+
+

mp_any<T…​> is mp_true if mp_to_bool<U> is mp_true for any type U in T…​, mp_false otherwise. Same as +mp_or, but does not perform short-circuit evaluation.

+
+
+
+
using R1 = mp_any<mp_true, mp_false>;  // mp_true
+using R2 = mp_any<mp_true, void>;      // compile-time error
+using R3 = mp_any<mp_false, mp_false>; // mp_false
+using R4 = mp_any<void, mp_true>;      // compile-time error
+
+
+
+
+

mp_same<T…​>

+
+
+
template<class... T> using mp_same = /*...*/;
+
+
+
+

mp_same<T…​> is mp_true if all the types in T…​ are the same type, mp_false otherwise. mp_same<> is mp_true.

+
+
+
+

mp_plus<T…​>

+
+
+
template<class... T> using mp_plus = /*...*/;
+
+
+
+

mp_plus<T…​> is an integral constant type with a value that is the sum of U::value for all types U in T…​. +mp_plus<> is mp_int<0>.

+
+
+
+
+

Bind, <boost/mp11/bind.hpp>

+
+

mp_arg<I>

+
+
+
template<std::size_t I> struct mp_arg;
+
+
+
+

mp_arg<I> is a quoted metafunction whose nested template fn<T…​> returns the I-th zero-based element of T…​.

+
+
+
+

_1, …​, _9

+
+
+
using _1 = mp_arg<0>;
+using _2 = mp_arg<1>;
+using _3 = mp_arg<2>;
+using _4 = mp_arg<3>;
+using _5 = mp_arg<4>;
+using _6 = mp_arg<5>;
+using _7 = mp_arg<6>;
+using _8 = mp_arg<7>;
+using _9 = mp_arg<8>;
+
+
+
+

_1 to _9 are placeholder types, the equivalent to the placeholders of boost::bind.

+
+
+
+

mp_bind<F, T…​>

+
+
+
template<template<class...> class F, class... T> struct mp_bind;
+
+
+
+

mp_bind<F, T…​> is a quoted metafunction that implements the type-based equivalent of boost::bind. Its nested +template fn<U…​> returns F<V…​>, where V…​ is T…​ with the placeholders replaced by the corresponding element +of U…​ and the mp_bind expressions replaced with their corresponding evaluations against U…​.

+
+
+

For example, mp_bind<F, int, _2, mp_bind<G, _1>>::fn<float, void> is F<int, void, G<float>>.

+
+
+
+

mp_bind_q<Q, T…​>

+
+
+
template<class Q, class... T> using mp_bind_q = mp_bind<Q::template fn, T...>;
+
+
+
+

As mp_bind, but takes a quoted metafunction.

+
+
+
+

mp_bind_front<F, T…​>

+
+
+
template<template<class...> class F, class... T> struct mp_bind_front;
+
+
+
+

mp_bind_front<F, T…​> binds the leftmost arguments of F to T…​. Its nested template fn<U…​> returns F<T…​, U…​>.

+
+
+
+

mp_bind_front_q<Q, T…​>

+
+
+
template<class Q, class... T> using mp_bind_front_q = mp_bind_front<Q::template fn, T...>;
+
+
+
+

As mp_bind_front, but takes a quoted metafunction.

+
+
+
+

mp_bind_back<F, T…​>

+
+
+
template<template<class...> class F, class... T> struct mp_bind_back;
+
+
+
+

mp_bind_back<F, T…​> binds the rightmost arguments of F to T…​. Its nested template fn<U…​> returns F<U…​, T…​>.

+
+
+
+

mp_bind_back_q<Q, T…​>

+
+
+
template<class Q, class... T> using mp_bind_back_q = mp_bind_back<Q::template fn, T...>;
+
+
+
+

As mp_bind_back, but takes a quoted metafunction.

+
+
+
+
+

Integer Sequences, <boost/mp11/integer_sequence.hpp>

+
+

integer_sequence<T, I…​>

+
+
+
template<class T, T... I> struct integer_sequence
+{
+};
+
+
+
+

integer_sequence<T, I…​> holds a sequence of integers of type T. Same as C++14’s std::integer_sequence.

+
+
+
+

make_integer_sequence<T, N>

+
+
+
template<class T, T N> using make_integer_sequence = /*...*/;
+
+
+
+

make_integer_sequence<T, N> is integer_sequence<T, 0, 1, …​, N-1>. Same as C++14’s std::make_integer_sequence.

+
+
+
+

index_sequence<I…​>

+
+
+
template<std::size_t... I> using index_sequence = integer_sequence<std::size_t, I...>;
+
+
+
+

index_sequence<I…​> is an alias for integer_sequence<size_t, I…​>. Same as C++14’s std::index_sequence.

+
+
+
+

make_index_sequence<N>

+
+
+
template<std::size_t N> using make_index_sequence = make_integer_sequence<std::size_t, N>;
+
+
+
+

make_index_sequence<N> is index_sequence<0, 1, …​, N-1>. Same as C++14’s std::make_index_sequence.

+
+
+
+

index_sequence_for<T…​>

+
+
+
template<class... T> using index_sequence_for = make_integer_sequence<std::size_t, sizeof...(T)>;
+
+
+
+

index_sequence_for<N> is make_index_sequence<sizeof…​(T)>. Same as C++14’s std::index_sequence_for.

+
+
+
+
+

A "for each" algorithm for tuple-like types, <boost/mp11/tuple_for_each.hpp>

+
+

tuple_for_each(tp, f)

+
+
+
template<class Tp, class F> constexpr F tuple_for_each(Tp&& tp, F&& f);
+
+
+
+

tuple_for_each(tp, f) applies the function object f to each element of tp by evaluating the +expression f(std::get<J>(std::forward<Tp>(tp))) for J in 0..N-1, where N is std::tuple_size<typename std::remove_reference<Tp>::type>::value.

+
+
+

Returns std::forward<F>(f).

+
+
+
+ + +
+ +
+
+

This documentation is

+
+
+ +
+
+
+ + - + \ No newline at end of file diff --git a/doc/mp11.adoc b/doc/mp11.adoc new file mode 100644 index 0000000..9d2a5fa --- /dev/null +++ b/doc/mp11.adoc @@ -0,0 +1,34 @@ +//// +Copyright 2017 Peter Dimov + +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +# Boost.Mp11 +Peter Dimov +:toc: left +:toclevels: 3 +:idprefix: + +:leveloffset: +1 + +include::mp11/overview.adoc[] + +include::mp11/definitions.adoc[] + +include::mp11/examples.adoc[] + +include::mp11/reference.adoc[] + +:leveloffset: -1 + +[appendix] +## Copyright and License + +This documentation is + +* Copyright 2017 Peter Dimov +* Distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0]. diff --git a/doc/mp11.qbk b/doc/mp11.qbk deleted file mode 100644 index 51e6b83..0000000 --- a/doc/mp11.qbk +++ /dev/null @@ -1,45 +0,0 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] - -[library Boost.Mp11 - [quickbook 1.6] - [id mp11] - [copyright 2015-2017 Peter Dimov] - [dirname mp11] - [license Distributed under the - [@http://boost.org/LICENSE_1_0.txt Boost Software License, - Version 1.0]. - ] -] - -[template simplesect[title] -[block ''''''[title]'''''']] - -[template endsimplesect[] -[block '''''']] - -[include mp11/overview.qbk] -[include mp11/definitions.qbk] -[include mp11/examples.qbk] - -[section Reference] - -The contents of the library are in namespace `boost::mp11`. - -[include mp11/integral.qbk] -[include mp11/list.qbk] -[include mp11/utility.qbk] -[include mp11/algorithm.qbk] -[include mp11/set.qbk] -[include mp11/map.qbk] -[include mp11/function.qbk] -[include mp11/bind.qbk] -[include mp11/integer_sequence.qbk] -[include mp11/tuple_for_each.qbk] - -[endsect] diff --git a/doc/mp11/algorithm.qbk b/doc/mp11/algorithm.adoc similarity index 81% rename from doc/mp11/algorithm.qbk rename to doc/mp11/algorithm.adoc index 98ec68d..0f45219 100644 --- a/doc/mp11/algorithm.qbk +++ b/doc/mp11/algorithm.adoc @@ -1,295 +1,301 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:algorithm Algorithms, ``] +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#algorithm] +# Algorithms, +:toc: +:toc-title: +:idprefix: + +## mp_assign -[section `mp_assign`] template using mp_assign = /*...*/; `mp_assign, L2>` is an alias for `L1`. That is, it replaces the elements of `L1` with those of `L2`. -[endsect] -[section `mp_clear`] +## mp_clear + template using mp_clear = mp_assign>; `mp_clear>` is an alias for `L<>`, that is, it removes the elements of `L`. -[endsect] -[section `mp_transform`] +## mp_transform + template class F, class... L> using mp_transform = /*...*/; `mp_transform, L2, ..., Ln>` applies `F` to each successive tuple of elements and returns `L1...>`. -[endsect] -[section `mp_transform_q`] +## mp_transform_q + template using mp_transform_q = mp_transform; As `mp_transform`, but takes a quoted metafunction. -[endsect] -[section `mp_transform_if`] +## mp_transform_if + template class P, template class F, class L...> using mp_transform_if = /*...*/; `mp_transform_if` replaces the elements of the list `L1` for which `mp_to_bool>` is `mp_true` with `F`, and returns the result, where `Ti` are the corresponding elements of `Li`. -[endsect] -[section `mp_transform_if_q`] +## mp_transform_if_q + template using mp_transform_if_q = mp_transform_if; As `mp_transform_if`, but takes a quoted metafunction. -[endsect] -[section `mp_fill`] +## mp_fill + template using mp_fill = /*...*/; `mp_fill, V>` returns `L`, with the result having the same size as the input. -[endsect] -[section `mp_count`] +## mp_count + template using mp_count = /*...*/; `mp_count` returns `mp_size_t`, where `N` is the number of elements of `L` same as `V`. -[endsect] -[section `mp_count_if`] +## mp_count_if + template class P> using mp_count_if = /*...*/; `mp_count_if` returns `mp_size_t`, where `N` is the number of elements `T` of `L` for which `mp_to_bool>` is `mp_true`. -[endsect] -[section `mp_contains`] +## mp_contains + template using mp_contains = mp_to_bool>; `mp_contains` is `mp_true` when `L` contains an element `V`, `mp_false` otherwise. -[endsect] -[section `mp_repeat_c`] +## mp_repeat_c + template using mp_repeat_c = /*...*/; `mp_repeat_c` returns a list of the same type as `L` that consists of `N` concatenated copies of `L`. -[endsect] -[section `mp_repeat`] +## mp_repeat + template using mp_repeat = /*...*/; Same as `mp_repeat_c` but with a type argument `N`. The number of copies is `N::value` and must be nonnegative. -[endsect] -[section `mp_product`] +## mp_product + template class F, class... L> using mp_product = /*...*/; `mp_product, L2, ..., Ln>` evaluates `F` for values `Ui` taken from the Cartesian product of the lists, as if the elements `Ui` are formed by `n` nested loops, each traversing `Li`. It returns a list of type `L1` containing the results of the application of `F`. -[endsect] -[section `mp_product_q`] +## mp_product_q + template using mp_product_q = mp_product; As `mp_product`, but takes a quoted metafunction. -[endsect] -[section `mp_drop_c`] +## mp_drop_c + template using mp_drop_c = /*...*/; `mp_drop_c` removes the first `N` elements of `L` and returns the result. -[endsect] -[section `mp_drop`] +## mp_drop + template using mp_drop = /*...*/; Same as `mp_drop_c`, but with a type argument `N`. `N::value` must be a nonnegative number. -[endsect] -[section `mp_iota_c`] +## mp_iota_c + template using mp_iota_c = /*...*/; `mp_iota_c` is an alias for `mp_list, mp_size_t<1>, ..., mp_size_t>`. -[endsect] -[section `mp_iota`] +## mp_iota + template using mp_iota = /*...*/; Same as `mp_iota_c`, but with a type argument `N`. `N::value` must be a nonnegative number. Returns `mp_list, std::integral_constant, ..., std::integral_constant>` where `T` is the type of `N::value`. -[endsect] -[section `mp_at_c`] +## mp_at_c + template using mp_at_c = /*...*/; `mp_at_c` returns the `I`th element of `L`, zero-based. -[endsect] -[section `mp_at`] +## mp_at + template using mp_at = /*...*/; Same as `mp_at_c`, but with a type argument `I`. `I::value` must be a nonnegative number. -[endsect] -[section `mp_take_c`] +## mp_take_c + template using mp_take_c = /*...*/; `mp_take_c` returns a list of the same type as `L` containing the first `N` elements of `L`. -[endsect] -[section `mp_take`] +## mp_take + template using mp_take = /*...*/; Same as `mp_take_c`, but with a type argument `N`. `N::value` must be a nonnegative number. -[endsect] -[section `mp_insert_c`] +## mp_insert_c + template using mp_insert_c = mp_append, mp_push_front, T...>>; Inserts the elements `T...` into the list `L` at position `I` (a zero-based index). -[endsect] -[section `mp_insert`] +## mp_insert + template using mp_insert = mp_append, mp_push_front, T...>>; Same as `mp_insert_c`, but with a type argument `I`. -[endsect] -[section `mp_erase_c`] +## mp_erase_c + template using mp_erase = mp_append, mp_drop_c>; Removes from the list `L` the elements with indices from `I` (inclusive) to `J` (exclusive). -[endsect] -[section `mp_erase`] +## mp_erase + template using mp_erase = mp_append, mp_drop>; Same as `mp_erase_c`, but with a type arguments `I` and `J`. -[endsect] -[section `mp_replace`] +## mp_replace + template using mp_replace = /*...*/; Replaces all `V` elements of `L` with `W` and returns the result. -[endsect] -[section `mp_replace_if`] +## mp_replace_if + template class P, class W> using mp_replace_if = /*...*/; Replaces all `T` elements of `L` for which `mp_to_bool>` is `mp_true` with `W` and returns the result. -[endsect] -[section `mp_replace_at_c`] +## mp_replace_at_c + template using mp_replace_at_c = /*...*/; Replaces the element of `L` at zero-based index `I` with `W` and returns the result. -[endsect] -[section `mp_replace_at`] +## mp_replace_at + template using mp_replace_at = /*...*/; Same as `mp_replace_at_c`, but with a type argument `I`. `I::value` must be a nonnegative number. -[endsect] -[section `mp_copy_if`] +## mp_copy_if + template class P> using mp_copy_if = /*...*/; Copies the elements `T` of `L` for which `mp_to_bool>` is `mp_true` to a new list of the same type and returns it. -[endsect] -[section `mp_remove`] +## mp_remove + template using mp_remove = /*...*/; Removes all `V` elements of `L` and returns the result. -[endsect] -[section `mp_remove_if`] +## mp_remove_if + template class P> using mp_remove_if = /*...*/; Removes all elements `T` of `L` for which `mp_to_bool>` is `mp_true` and returns the result. -[endsect] -[section `mp_partition`] +## mp_partition + template class P> using mp_partition = /*...*/; `mp_partition, P>` partitions `L` into two lists `L` and `L` such that `mp_to_bool>` is `mp_true` for the elements of `L` and `mp_false` for the elements of `L`. Returns `L, L>`. -[endsect] -[section `mp_sort`] +## mp_sort + template class P> using mp_sort = /*...*/; `mp_sort` sorts the list `L` according to the strict weak ordering `mp_to_bool>`. -[endsect] -[section `mp_find`] +## mp_find + template using mp_find = /*...*/; `mp_find` returns the index at which the type `V` is located in the list `L`. It's an alias for `mp_size_t`, where `I` is the zero-based index of the first occurence of `V` in `L`. If `L` does not contain `V`, `mp_find` is `mp_size`. -[endsect] -[section `mp_find_if`] +## mp_find_if + template class P> using mp_find_if = /*...*/; `mp_find_f` is an alias for `mp_size_t`, where `I` is the zero-based index of the first element `T` in `L` for which `mp_to_bool>` is `mp_true`. If there is no such element, `mp_find_if` is `mp_size`. -[endsect] -[section `mp_reverse`] +## mp_reverse + template using mp_reverse = /*...*/; `mp_reverse>` is `L`. -[endsect] -[section `mp_fold`] +## mp_fold + template class F> using mp_fold = /*...*/; `mp_fold, V, F>` is `F< F< F< F, T2>, ...>, Tn>`, or `V`, if `L` is empty. -[endsect] -[section `mp_reverse_fold`] +## mp_reverse_fold + template class F> using mp_reverse_fold = /*...*/; `mp_reverse_fold, V, F>` is `F>>>`, or `V`, if `L` is empty. -[endsect] -[section `mp_unique`] +## mp_unique + template using mp_unique = /*...*/; `mp_unique` returns a list of the same type as `L` with the duplicate elements removed. -[endsect] -[section `mp_all_of`] +## mp_all_of + template class P> using mp_all_of = mp_bool< mp_count_if::value == mp_size::value >; `mp_all_of` is `mp_true` when `P` holds for all elements of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_true`. -[endsect] -[section `mp_none_of`] +## mp_none_of + template class P> using mp_none_of = mp_bool< mp_count_if::value == 0 >; `mp_none_of` is `mp_true` when `P` holds for no element of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_true`. -[endsect] -[section `mp_any_of`] +## mp_any_of + template class P> using mp_any_of = mp_bool< mp_count_if::value != 0 >; `mp_any_of` is `mp_true` when `P` holds for at least one element of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_false`. -[endsect] -[section `mp_for_each(f)`] +## mp_for_each(f) + template constexpr F mp_for_each(F&& f); `mp_for_each(f)` calls `f` with `T()` for each element `T` of the list `L`, in order. Returns `std::forward(f)`. -[endsect] -[section `mp_with_index(i, f)`] +## mp_with_index(i, f) + template decltype(std::declval()(std::declval>())) mp_with_index( std::size_t i, F && f ); `mp_with_index(i, f)` calls `f` with `mp_size_t()` and returns the result. `i` must be less than `N`. @@ -297,6 +303,3 @@ Returns `std::forward(f)`. template decltype(std::declval()(std::declval>())) mp_with_index( std::size_t i, F && f ); Returns `mp_with_index(i, f)`. -[endsect] - -[endsect:algorithm] diff --git a/doc/mp11/bind.qbk b/doc/mp11/bind.adoc similarity index 75% rename from doc/mp11/bind.qbk rename to doc/mp11/bind.adoc index f254929..6993f09 100644 --- a/doc/mp11/bind.qbk +++ b/doc/mp11/bind.adoc @@ -1,20 +1,26 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:bind Bind, ``] +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#bind] +# Bind, +:toc: +:toc-title: +:idprefix: + +## mp_arg -[section `mp_arg`] template struct mp_arg; `mp_arg` is a quoted metafunction whose nested template `fn` returns the `I`-th zero-based element of `T...`. -[endsect] -[section `_1`, ..., `_9`] +## _1, ..., _9 + using _1 = mp_arg<0>; using _2 = mp_arg<1>; using _3 = mp_arg<2>; @@ -26,9 +32,9 @@ using _9 = mp_arg<8>; `_1` to `_9` are placeholder types, the equivalent to the placeholders of `boost::bind`. -[endsect] -[section `mp_bind`] +## mp_bind + template class F, class... T> struct mp_bind; `mp_bind` is a quoted metafunction that implements the type-based equivalent of `boost::bind`. Its nested @@ -36,36 +42,33 @@ template `fn` returns `F`, where `V...` is `T...` with the placehold of `U...` and the `mp_bind` expressions replaced with their corresponding evaluations against `U...`. For example, `mp_bind>::fn` is `F>`. -[endsect] -[section `mp_bind_q`] +## mp_bind_q + template using mp_bind_q = mp_bind; As `mp_bind`, but takes a quoted metafunction. -[endsect] -[section `mp_bind_front`] +## mp_bind_front + template class F, class... T> struct mp_bind_front; `mp_bind_front` binds the leftmost arguments of `F` to `T...`. Its nested template `fn` returns `F`. -[endsect] -[section `mp_bind_front_q`] +## mp_bind_front_q + template using mp_bind_front_q = mp_bind_front; As `mp_bind_front`, but takes a quoted metafunction. -[endsect] -[section `mp_bind_back`] +## mp_bind_back + template class F, class... T> struct mp_bind_back; `mp_bind_back` binds the rightmost arguments of `F` to `T...`. Its nested template `fn` returns `F`. -[endsect] -[section `mp_bind_back_q`] +## mp_bind_back_q + template using mp_bind_back_q = mp_bind_back; As `mp_bind_back`, but takes a quoted metafunction. -[endsect] - -[endsect:bind] diff --git a/doc/mp11/definitions.qbk b/doc/mp11/definitions.adoc similarity index 61% rename from doc/mp11/definitions.qbk rename to doc/mp11/definitions.adoc index 3955fbf..f3ebad3 100644 --- a/doc/mp11/definitions.qbk +++ b/doc/mp11/definitions.adoc @@ -1,39 +1,39 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:definitions Definitions] +Distributed under the Boost Software License, Version 1.0. -A /list/ is a '''—''' usually but not necessarily variadic '''—''' template class whose parameters are all types, +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#definitions] +# Definitions + +A _list_ is a -- usually but not necessarily variadic -- template class whose parameters are all types, for example `mp_list`, `mp_list<>`, `std::tuple`, `std::pair`, `std::shared_ptr`. -A /metafunction/ is a class template or a template alias whose parameters are all types, for example `std::add_pointer_t`, +A _metafunction_ is a class template or a template alias whose parameters are all types, for example `std::add_pointer_t`, `std::is_const`, `mp_second`, `mp_push_front`, `mp_list`, `std::tuple`, `std::pair`, `std::shared_ptr`, or template using F1 = void; template using F2 = T*; template using F3 = std::integral_constant; -A /quoted metafunction/ is a class with a public metafunction member called `fn`, for example +A _quoted metafunction_ is a class with a public metafunction member called `fn`, for example struct Q1 { template using fn = void; }; struct Q2 { template using fn = T*; }; struct Q3 { template using fn = std::integral_constant; }; -An /integral constant type/ is a class with a public member `value` that is an integral constant in the C++ sense. For example, +An _integral constant type_ is a class with a public member `value` that is an integral constant in the C++ sense. For example, `std::integral_constant`, or struct N { static int constexpr value = 2; }; -A /set/ is a list whose elements are unique. +A _set_ is a list whose elements are unique. -A /map/ is a list of lists, the inner lists having at least one element (the key.) The keys of the map must be unique. For example, +A _map_ is a list of lists, the inner lists having at least one element (the key.) The keys of the map must be unique. For example, using M1 = std::tuple, std::pair, std::pair>; using M2 = mp_list, mp_list, mp_list>; - -[endsect:definitions] diff --git a/doc/mp11/examples.qbk b/doc/mp11/examples.adoc similarity index 54% rename from doc/mp11/examples.qbk rename to doc/mp11/examples.adoc index a75b9f1..717d93c 100644 --- a/doc/mp11/examples.qbk +++ b/doc/mp11/examples.adoc @@ -1,32 +1,41 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:examples Examples] +Distributed under the Boost Software License, Version 1.0. -[section Generating Test Cases] +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#examples] +# Examples +:toc: +:toc-title: +:idprefix: + +## Generating Test Cases Let's suppose that we have written a metafunction `result`: - template using promote = typename std::common_type::type; - template using result = typename std::common_type, promote>::type; +``` +template using promote = typename std::common_type::type; + +template using result = + typename std::common_type, promote>::type; +``` that ought to represent the result of an arithmetic operation on the integer types `T` and `U`, for example `t + u`. We want to test whether `result` gives correct results for various combinations of `T` and `U`, so we write the function +``` +template void test_result() +{ + using T3 = decltype( T1() + T2() ); + using T4 = result; - template void test_result() - { - using T3 = decltype( T1() + T2() ); - using T4 = result; - - std::cout << ( std::is_same::value? "[PASS]": "[FAIL]" ) << std::endl; - } - + std::cout << ( std::is_same::value? "[PASS]": "[FAIL]" ) << std::endl; +} +``` and then need to call it a substantial number of times: int main() @@ -40,38 +49,41 @@ and then need to call it a substantial number of times: Writing all those type combinations by hand is unwieldy, error prone, and worst of all, boring. This is how we can leverage Mp11 to automate the task: +``` +#include +#include +#include +#include +#include - #include - #include - #include - #include - #include +using namespace boost::mp11; - using namespace boost::mp11; +template std::string name() +{ + return boost::core::demangle( typeid(T).name() ); +} - template std::string name() - { - return boost::core::demangle( typeid(T).name() ); - } +template using promote = typename std::common_type::type; - template using promote = typename std::common_type::type; - template using result = typename std::common_type, promote>::type; +template using result = + typename std::common_type, promote>::type; - template void test_result( mp_list const& ) - { - using T3 = decltype( T1() + T2() ); - using T4 = result; +template void test_result( mp_list const& ) +{ + using T3 = decltype( T1() + T2() ); + using T4 = result; - std::cout << ( std::is_same::value? "[PASS] ": "[FAIL] " ) - << name() << " + " << name() << " -> " << name() << ", result: " << name() << std::endl; - } - - int main() - { - using L = std::tuple; - tuple_for_each( mp_product(), [](auto&& x){ test_result(x); } ); - } + std::cout << ( std::is_same::value? "[PASS] ": "[FAIL] " ) + << name() << " + " << name() << " -> " << name() + << ", result: " << name() << std::endl; +} +int main() +{ + using L = std::tuple; + tuple_for_each( mp_product(), [](auto&& x){ test_result(x); } ); +} +``` How does it work? `mp_product` calls `F` where `T1` varies over the elements of `L1` and `T2` varies over @@ -86,28 +98,27 @@ tuple element; we use a (C++14) lambda that calls `test_result`. In pure C++11, we can't use a lambda with an `auto&&` parameter, so we'll have to make `test_result` a function object with a templated `operator()` and pass that to `tuple_for_each` directly: - - struct test_result +``` +struct test_result +{ + template void operator()( mp_list const& ) const { - template void operator()( mp_list const& ) const - { - using T3 = decltype( T1() + T2() ); - using T4 = result; + using T3 = decltype( T1() + T2() ); + using T4 = result; - std::cout << ( std::is_same::value? "[PASS] ": "[FAIL] " ) - << name() << " + " << name() << " -> " << name() << ", result: " << name() << std::endl; - } - }; - - int main() - { - using L = std::tuple; - tuple_for_each( mp_product(), test_result() ); + std::cout << ( std::is_same::value? "[PASS] ": "[FAIL] " ) + << name() << " + " << name() << " -> " << name() + << ", result: " << name() << std::endl; } +}; -[endsect] - -[section Writing `common_type` specializations] +int main() +{ + using L = std::tuple; + tuple_for_each( mp_product(), test_result() ); +} +``` +## Writing `common_type` specializations The standard trait `std::common_type`, used to obtain a type to which all of its arguments can convert without unnecessary loss of precision, can be user-specialized when its default implementation (based on the ternary `?:` @@ -115,27 +126,31 @@ operator) is unsuitable. Let's write a `common_type` specialization for two `std::tuple` arguments. For that, we need a metafunction that applies `std::common_type` to each pair of elements and gathers the results into a tuple: +``` +template using common_type_t = + typename std::common_type::type; // standard in C++14 - template using common_type_t = typename std::common_type::type; // standard in C++14 - - template using common_tuple = mp_transform; - +template using common_tuple = + mp_transform; +``` then specialize `common_type` to use it: +``` +namespace std +{ - namespace std + template + struct common_type, std::tuple>: + mp_defer, std::tuple> { + }; - template struct common_type, std::tuple>: mp_defer, std::tuple> - { - }; - - } // std - +} // std +``` (There is no need to specialize `std::common_type` for more than two arguments - it takes care of synthesizing the appropriate semantics from the binary case.) The subtlety here is the use of `mp_defer`. We could have defined a nested `type` to `common_tuple, std::tuple>`, -and it would still have worked in all valid cases. By letting `mp_defer` define `type`, though, we make our specialization /SFINAE-friendly/. +and it would still have worked in all valid cases. By letting `mp_defer` define `type`, though, we make our specialization _SFINAE-friendly_. That is, when our `common_tuple` causes a substitution failure instead of a hard error, `mp_defer` will not define a nested `type`, and `common_type_t`, which is defined as `typename common_type<...>::type`, will also cause a substitution failure. @@ -146,88 +161,89 @@ or an unsucessful return with an error code of some type in the list `E...`. The combined into their common type, and we take the union of the set of error types. Therefore, +``` +template using common_expected = + mp_rename>, common_type_t>, expected>; - template using common_expected = mp_rename>, common_type_t>, expected>; +namespace std +{ - namespace std + template + struct common_type, expected>: + mp_defer, T2, mp_list> { + }; - template struct common_type, expected>: mp_defer, T2, mp_list> - { - }; - - } // std - +} // std +``` Here we've taken a different tack; instead of passing the `expected` types to `common_expected`, we're passing the `T` types and lists of the `E` types. This makes our job easier. `mp_unique>` gives us the concatenation of `E1` and `E2` with the duplicates removed; we then add `common_type_t` to the front via `mp_push_front`; and finally, we `mp_rename` the resultant `mp_list` to `expected`. -[endsect] +## Fixing `tuple_cat` -[section Fixing `tuple_cat`] - -The article [@http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html Simple C++11 metaprogramming] builds an +The article http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html#[Simple C++11 metaprogramming] builds an implementation of the standard function `tuple_cat`, with the end result given below: +``` +template using F = mp_iota>; - template using F = mp_iota>; +template +R tuple_cat_( mp_list, mp_list, Tp tp ) +{ + return R{ std::get(std::get(tp))... }; +} - template - R tuple_cat_( mp_list, mp_list, Tp tp ) - { - return R{ std::get(std::get(tp))... }; - } +template, typename std::remove_reference::type...>> + R tuple_cat( Tp &&... tp ) +{ + std::size_t const N = sizeof...(Tp); - template, typename std::remove_reference::type...>> - R tuple_cat( Tp &&... tp ) - { - std::size_t const N = sizeof...(Tp); + // inner - // inner + using list1 = mp_list::type, mp_list>...>; + using list2 = mp_iota_c; - using list1 = mp_list::type, mp_list>...>; - using list2 = mp_iota_c; + using list3 = mp_transform; - using list3 = mp_transform; + using inner = mp_apply; - using inner = mp_apply; + // outer - // outer + using list4 = mp_transform; - using list4 = mp_transform; + using outer = mp_apply; - using outer = mp_apply; - - // - - return tuple_cat_( inner(), outer(), std::forward_as_tuple( std::forward(tp)... ) ); - } + // + return tuple_cat_( inner(), outer(), std::forward_as_tuple( std::forward(tp)... ) ); +} +``` This function, however, is not entirely correct, in that it doesn't handle some cases properly. For example, trying to concatenate tuples containing move-only elements such as `unique_ptr` fails: +``` +std::tuple> t1; +std::tuple> t2; - std::tuple> t1; - std::tuple> t2; - - auto result = ::tuple_cat( std::move( t1 ), std::move( t2 ) ); - +auto result = ::tuple_cat( std::move( t1 ), std::move( t2 ) ); +``` Trying to concatenate `const` tuples fails: +``` +std::tuple const t1; +std::tuple const t2; - std::tuple const t1; - std::tuple const t2; - - auto result = ::tuple_cat( t1, t2 ); - +auto result = ::tuple_cat( t1, t2 ); +``` And finally, the standard `tuple_cat` is specified to work on arbitrary tuple-like types (that is, all types that support `tuple_size`, `tuple_element`, and `get`), while our implementation only works with `tuple` and `pair`. `std::array`, for example, fails: +``` +std::array t1{ 1, 2 }; +std::array t2{ 3.0f, 4.0f, 5.0f }; - std::array t1{ 1, 2 }; - std::array t2{ 3.0f, 4.0f, 5.0f }; - - auto result = ::tuple_cat( t1, t2 ); - +auto result = ::tuple_cat( t1, t2 ); +``` Let's fix these one by one. Support for move-only types is easy, if one knows where to look. The problem is that `Tp` that we're passing to the helper `tuple_cat_` is (correctly) `tuple&&, unique_ptr&&>`, but `std::get<0>(tp)` still returns `unique_ptr&`, because `tp` is an lvalue. This behavior is a bit @@ -250,19 +266,19 @@ primitive that is inexplicably missing from the standard library: typename std::remove_reference::type>::type; and then by using `remove_cv_ref` in place of `typename std::remove_reference::type`: +``` +template, remove_cv_ref...>> + R tuple_cat( Tp &&... tp ) +{ + std::size_t const N = sizeof...(Tp); - template, remove_cv_ref...>> - R tuple_cat( Tp &&... tp ) - { - std::size_t const N = sizeof...(Tp); - - // inner - - using list1 = mp_list, mp_list>...>; - - // ... + // inner + using list1 = mp_list, mp_list>...>; + + // ... +``` Finally, tuple-like types. We've so far exploited the fact that `std::pair` and `std::tuple` are valid Mp11 lists, but in general, arbitrary tuple-like types aren't, so we need to convert them into such. For that, we'll need to define a metafunction `from_tuple_like` that will take an arbitrary tuple-like type and will return, in our case, @@ -273,10 +289,13 @@ convenient. What we need is, given a tuple-like type `Tp`, to obtain `mp_list::type, std::tuple_element<1, Tp>::type, ..., std::tuple_element::type>`, where `N` is `tuple_size::value`. Here's one way to do it: +``` +template using tuple_element = + typename std::tuple_element::type; - template using tuple_element = typename std::tuple_element::type; - template using from_tuple_like = mp_product, mp_iota>>; - +template using from_tuple_like = + mp_product, mp_iota>>; +``` (`mp_iota` is an algorithm that returns an `mp_list` with elements `mp_size_t<0>`, `mp_size_t<1>`, ..., `mp_size_t`.) Remember that `mp_product` performs the equivalent of two nested loops over the elements of `L1` and `L2`, @@ -287,57 +306,59 @@ as `L1` (an `mp_list`) with contents `tuple_element>`, `tuple_el For completeness's sake, here's another, more traditional way to achieve the same result: - template using from_tuple_like = mp_transform_q, mp_iota>>; + template using from_tuple_like = + mp_transform_q, mp_iota>>; With all these fixes applied, our fully operational `tuple_cat` now looks like this: +``` +template using F = mp_iota>; - template using F = mp_iota>; +template +R tuple_cat_( mp_list, mp_list, Tp tp ) +{ + return R{ std::get(std::get(std::move(tp)))... }; +} - template - R tuple_cat_( mp_list, mp_list, Tp tp ) - { - return R{ std::get(std::get(std::move(tp)))... }; - } +template using remove_cv_ref = typename std::remove_cv< + typename std::remove_reference::type>::type; - template using remove_cv_ref = typename std::remove_cv< - typename std::remove_reference::type>::type; +template using tuple_element = + typename std::tuple_element::type; + +template using from_tuple_like = + mp_product, mp_iota>>; - template using tuple_element = typename std::tuple_element::type; - template using from_tuple_like = mp_product, mp_iota>>; +template, from_tuple_like>...>> + R tuple_cat( Tp &&... tp ) +{ + std::size_t const N = sizeof...(Tp); - template, from_tuple_like>...>> - R tuple_cat( Tp &&... tp ) - { - std::size_t const N = sizeof...(Tp); + // inner - // inner + using list1 = mp_list>...>; + using list2 = mp_iota_c; - using list1 = mp_list>...>; - using list2 = mp_iota_c; + using list3 = mp_transform; - using list3 = mp_transform; + using inner = mp_apply; - using inner = mp_apply; + // outer - // outer + using list4 = mp_transform; - using list4 = mp_transform; + using outer = mp_apply; - using outer = mp_apply; + // - // - - return tuple_cat_( inner(), outer(), std::forward_as_tuple( std::forward(tp)... ) ); - } - -[endsect] - -[section Computing Return Types] + return tuple_cat_( inner(), outer(), std::forward_as_tuple( std::forward(tp)... ) ); +} +``` +## Computing Return Types C++17 has a standard variant type, called `std::variant`. It also defines a function template -`std::visit` that can be used to apply a function to the contained value of one or more `variant`s. -So for instance, if the `variant` `v1` contains `1`, and the `variant` `v2` contains `2.0f`, +`std::visit` that can be used to apply a function to the contained value of one or more variants. +So for instance, if the variant `v1` contains `1`, and the variant `v2` contains `2.0f`, `std::visit(f, v1, v2)` will call `f(1, 2.0f)`. However, `std::visit` has one limitation: it cannot return a result unless all @@ -351,13 +372,16 @@ what `v1` and `v2` hold. A type that can hold either `int` or `float` already exists, called, surprisingly enough, `std::variant`. Let's write our own function template `rvisit` that is the same as `visit` but returns a `variant`: +``` +template auto rvisit( F&& f, V&&... v ) +{ + using R = /*...*/; - template auto rvisit( F&& f, V&&... v ) - { - using R = /*...*/; - return std::visit( [&]( auto&&... x ){ return R( std::forward(f)( std::forward(x)... ) ); }, std::forward( v )... ); - } - + return std::visit( [&]( auto&&... x ) + { return R( std::forward(f)( std::forward(x)... ) ); }, + std::forward( v )... ); +} +``` What this does is basically calls `std::visit` to do the work, but instead of passing it `f`, we pass a lambda that does the same as `f` except it converts the result to a common type `R`. `R` is supposed to be `std::variant<...>` where the ellipsis denotes the return types of calling `f` with all possible combinations of variant values. @@ -383,53 +407,57 @@ One more step remains. Suppose that, as above, we're passing two variants of typ `[]( auto const& x, auto const& y ){ return x + y; }`. This will generate `R` of length 9, one per each combination, but many of those elements will be the same, either `int` or `float`, and we need to filter out the duplicates. So, - using R = mp_unique::template fn, std::remove_reference_t...>>; + using R = mp_unique, std::remove_reference_t...>>; and we're done: +``` +#include +#include +#include +#include +#include +#include - #include - #include - #include - #include - #include - #include +using namespace boost::mp11; - using namespace boost::mp11; +template struct Qret +{ + template using fn = decltype( std::declval()( std::declval()... ) ); +}; - template struct Qret - { - template using fn = decltype( std::declval()( std::declval()... ) ); - }; +template auto rvisit( F&& f, V&&... v ) +{ + using R = mp_unique, std::remove_reference_t...>>; - template auto rvisit( F&& f, V&&... v ) - { - using R = mp_unique, std::remove_reference_t...>>; - return std::visit( [&]( auto&&... x ){ return R( std::forward(f)( std::forward(x)... ) ); }, std::forward( v )... ); - } + return std::visit( [&]( auto&&... x ) + { return R( std::forward(f)( std::forward(x)... ) ); }, + std::forward( v )... ); +} - template std::string name() - { - return boost::core::demangle( typeid(T).name() ); - } +template std::string name() +{ + return boost::core::demangle( typeid(T).name() ); +} - int main() - { - std::variant v1( 1 ); +int main() +{ + std::variant v1( 1 ); - std::cout << "(" << name() << ")v1: "; - std::visit( []( auto const& x ){ std::cout << "(" << name() << ")" << x << std::endl; }, v1 ); + std::cout << "(" << name() << ")v1: "; + std::visit( []( auto const& x ) + { std::cout << "(" << name() << ")" << x << std::endl; }, v1 ); - std::variant v2( 2.0f ); + std::variant v2( 2.0f ); - std::cout << "(" << name() << ")v2: "; - std::visit( []( auto const& x ){ std::cout << "(" << name() << ")" << x << std::endl; }, v2 ); + std::cout << "(" << name() << ")v2: "; + std::visit( []( auto const& x ) + { std::cout << "(" << name() << ")" << x << std::endl; }, v2 ); - auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 ); + auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 ); - std::cout << "(" << name() << ")v3: "; - std::visit( []( auto const& x ){ std::cout << "(" << name() << ")" << x << std::endl; }, v3 ); - } - -[endsect] - -[endsect:examples] + std::cout << "(" << name() << ")v3: "; + std::visit( []( auto const& x ) + { std::cout << "(" << name() << ")" << x << std::endl; }, v3 ); +} +``` diff --git a/doc/mp11/function.qbk b/doc/mp11/function.adoc similarity index 83% rename from doc/mp11/function.qbk rename to doc/mp11/function.adoc index ab1cb96..66168c2 100644 --- a/doc/mp11/function.qbk +++ b/doc/mp11/function.adoc @@ -1,20 +1,26 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:function Helper Metafunctions, ``] +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#function] +# Helper Metafunctions, +:toc: +:toc-title: +:idprefix: + +## mp_void -[section `mp_void`] template using mp_void = void; Same as `std::void_t` from C++17. -[endsect] -[section `mp_and`] +## mp_and + template using mp_and = /*...*/; `mp_and` applies `mp_to_bool` to the types in `T...`, in order. If the result of an application is `mp_false`, `mp_and` @@ -25,9 +31,9 @@ returns `mp_true`. `mp_and<>` is `mp_true`. using R2 = mp_and; // mp_false, void is not reached using R3 = mp_and; // mp_false using R4 = mp_and; // mp_false (!) -[endsect] -[section `mp_all`] +## mp_all + template using mp_all = /*...*/; `mp_all` is `mp_true` if `mp_to_bool` is `mp_true` for all types `U` in `T...`, `mp_false` otherwise. Same as @@ -39,9 +45,9 @@ mask substitution failures as `mp_and` does. using R2 = mp_and; // compile-time error using R3 = mp_and; // mp_false using R4 = mp_and; // compile-time error -[endsect] -[section `mp_or`] +## mp_or + template using mp_or = /*...*/; `mp_or` applies `mp_to_bool` to the types in `T...`, in order. If the result of an application is `mp_true`, `mp_or` @@ -51,9 +57,9 @@ returns `mp_true`. If all results are `mp_false`, returns `mp_false`. `mp_or<>` using R2 = mp_or; // mp_true, void is not reached using R3 = mp_or; // mp_false using R4 = mp_or; // compile-time error -[endsect] -[section `mp_any`] +## mp_any + template using mp_any = /*...*/; `mp_any` is `mp_true` if `mp_to_bool` is `mp_true` for any type `U` in `T...`, `mp_false` otherwise. Same as @@ -63,19 +69,16 @@ returns `mp_true`. If all results are `mp_false`, returns `mp_false`. `mp_or<>` using R2 = mp_any; // compile-time error using R3 = mp_any; // mp_false using R4 = mp_any; // compile-time error -[endsect] -[section `mp_same`] +## mp_same + template using mp_same = /*...*/; `mp_same` is `mp_true` if all the types in `T...` are the same type, `mp_false` otherwise. `mp_same<>` is `mp_true`. -[endsect] -[section `mp_plus`] +## mp_plus + template using mp_plus = /*...*/; `mp_plus` is an integral constant type with a value that is the sum of `U::value` for all types `U` in `T...`. `mp_plus<>` is `mp_int<0>`. -[endsect] - -[endsect:function] diff --git a/doc/mp11/integer_sequence.qbk b/doc/mp11/integer_sequence.adoc similarity index 64% rename from doc/mp11/integer_sequence.qbk rename to doc/mp11/integer_sequence.adoc index 199634a..66c178e 100644 --- a/doc/mp11/integer_sequence.qbk +++ b/doc/mp11/integer_sequence.adoc @@ -1,43 +1,46 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:integer_sequence Integer Sequences, ``] +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#integer_sequence] +# Integer Sequences, +:toc: +:toc-title: +:idprefix: + +## integer_sequence -[section `integer_sequence`] template struct integer_sequence { }; `integer_sequence` holds a sequence of integers of type `T`. Same as C++14's `std::integer_sequence`. -[endsect] -[section `make_integer_sequence`] +## make_integer_sequence + template using make_integer_sequence = /*...*/; `make_integer_sequence` is `integer_sequence`. Same as C++14's `std::make_integer_sequence`. -[endsect] -[section `index_sequence`] +## index_sequence + template using index_sequence = integer_sequence; `index_sequence` is an alias for `integer_sequence`. Same as C++14's `std::index_sequence`. -[endsect] -[section `make_index_sequence`] +## make_index_sequence + template using make_index_sequence = make_integer_sequence; `make_index_sequence` is `index_sequence<0, 1, ..., N-1>`. Same as C++14's `std::make_index_sequence`. -[endsect] -[section `index_sequence_for`] +## index_sequence_for + template using index_sequence_for = make_integer_sequence; `index_sequence_for` is `make_index_sequence`. Same as C++14's `std::index_sequence_for`. -[endsect] - -[endsect:integer_sequence] diff --git a/doc/mp11/integral.qbk b/doc/mp11/integral.adoc similarity index 51% rename from doc/mp11/integral.qbk rename to doc/mp11/integral.adoc index dbe757f..7def22b 100644 --- a/doc/mp11/integral.qbk +++ b/doc/mp11/integral.adoc @@ -1,41 +1,44 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:integral Integral Constants, ``] +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#integral] +# Integral Constants, +:toc: +:toc-title: +:idprefix: For an Mp11 integral constant type `T`, `T::value` is an integral constant in the C++ sense. -[section `mp_bool`] +## mp_bool + template using mp_bool = std::integral_constant; -[endsect] -[section `mp_true`] +## mp_true + using mp_true = mp_bool; -[endsect] -[section `mp_false`] +## mp_false + using mp_false = mp_bool; -[endsect] -[section `mp_to_bool`] +## mp_to_bool + template using mp_to_bool = mp_bool(T::value)>; -[endsect] -[section `mp_not`] +## mp_not + template using mp_not = mp_bool< !T::value >; -[endsect] -[section `mp_int`] +## mp_int + template using mp_int = std::integral_constant; -[endsect] -[section `mp_size_t`] +## mp_size_t + template using mp_size_t = std::integral_constant; -[endsect] - -[endsect:integral] diff --git a/doc/mp11/list.qbk b/doc/mp11/list.adoc similarity index 80% rename from doc/mp11/list.qbk rename to doc/mp11/list.adoc index 6f96665..73c5a26 100644 --- a/doc/mp11/list.qbk +++ b/doc/mp11/list.adoc @@ -1,110 +1,116 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:list List Operations, ``] +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#list] +# List Operations, +:toc: +:toc-title: +:idprefix: + +## mp_list -[section `mp_list`] template struct mp_list {}; `mp_list` is the standard list type of Mp11, although the library is not restricted to it and can operate on arbitrary class templates such as `std::tuple` or `std::variant`. Even `std::pair` can be used if the transformation does not alter the number of the elements in the list. -[endsect] -[section `mp_size`] +## mp_size + template using mp_size = /*...*/; `mp_size` returns the number of elements in the list `L`, as a `mp_size_t`. In other words, `mp_size>` is an alias for `mp_size_t`. using L1 = mp_list<>; - using R1 = mp_size; // mp_size_t<0> - - using L2 = std::pair; - using R2 = mp_size; // mp_size_t<2> - - using L3 = std::tuple; - using R3 = mp_size; // mp_size_t<1> -[endsect] + using R1 = mp_size; // mp_size_t\<0> + + using L2 = std::pair; + using R2 = mp_size; // mp_size_t\<2> + + using L3 = std::tuple; + using R3 = mp_size; // mp_size_t\<1> + +## mp_empty -[section `mp_empty`] template using mp_empty = mp_bool::value == 0>; `mp_empty` is an alias for `mp_true` if the list `L` is empty, for `mp_false` otherwise. -[endsect] -[section `mp_front`] +## mp_front + template using mp_front = /*...*/; `mp_front` is the first element of the list `L`. That is, `mp_front>` is an alias for `T1`. using L1 = std::pair; using R1 = mp_front; // int - + using L2 = std::tuple; using R2 = mp_front; // float - + using L3 = mp_list; using R3 = mp_front; // char[1] -[endsect] -[section `mp_pop_front`] +## mp_pop_front + template using mp_pop_front = /*...*/; `mp_pop_front` removes the first element of the list `L`. That is, `mp_pop_front>` is an alias for `L`. using L1 = std::tuple; using R1 = mp_pop_front; // std::tuple - + using L2 = mp_list; using R2 = mp_pop_front; // mp_list<> -[endsect] -[section `mp_first`] +## mp_first + template using mp_first = mp_front; `mp_first` is another name for `mp_front`. -[endsect] -[section `mp_rest`] +## mp_rest + template using mp_rest = mp_pop_front; `mp_rest` is another name for `mp_pop_front`. -[endsect] -[section `mp_second`] +## mp_second + template using mp_second = /*...*/; `mp_second` is the second element of the list `L`. That is, `mp_second>` is an alias for `T2`. using L1 = std::pair; using R1 = mp_second; // float - + using L2 = std::tuple; using R2 = mp_second; // double - + using L3 = mp_list; using R3 = mp_second; // char[2] -[endsect] -[section `mp_third`] +## mp_third + template using mp_third = /*...*/; `mp_third` is the third element of the list `L`. That is, `mp_third>` is an alias for `T3`. using L1 = std::tuple; using R1 = mp_third; // long double - + using L2 = mp_list; using R2 = mp_third; // char[3] -[endsect] -[section `mp_push_front`] +## mp_push_front + template using mp_push_front = /*...*/; `mp_push_front` inserts the elements `T...` at the front of the list `L`. That is, `mp_push_front, T...>` @@ -112,12 +118,12 @@ is an alias for `L`. using L1 = std::tuple; using R1 = mp_push_front; // std::tuple - + using L2 = mp_list; using R2 = mp_push_front; // mp_list -[endsect] -[section `mp_push_back`] +## mp_push_back + template using mp_push_back = /*...*/; `mp_push_back` inserts the elements `T...` at the back of the list `L`. That is, `mp_push_back, T...>` @@ -125,24 +131,24 @@ is an alias for `L`. using L1 = std::tuple; using R1 = mp_push_back; // std::tuple - + using L2 = mp_list; using R2 = mp_push_back; // mp_list -[endsect] -[section `mp_rename`] +## mp_rename + template class Y> using mp_rename = /*...*/; `mp_rename` changes the type of the list `L` to `Y`. That is, `mp_rename, Y>` is an alias for `Y`. using L1 = std::pair; using R1 = mp_rename; // std::tuple - + using L2 = std::tuple; using R2 = mp_rename; // mp_list -[endsect] -[section `mp_apply`] +## mp_apply + template class F, class L> using mp_apply = mp_rename; `mp_apply` applies the metafunction `F` to the contents of the list `L`, that is, `mp_apply>` is an alias for `F`. @@ -150,33 +156,35 @@ is an alias for `L`. using L1 = std::pair; using R1 = mp_apply; // std::is_same -[endsect] -[section `mp_apply_q`] +## mp_apply_q + template using mp_apply_q = mp_apply; Same as `mp_apply`, but takes a quoted metafunction. +``` +using L1 = std::tuple; +using L2 = mp_list; - using L1 = std::tuple; - using L2 = mp_list; - using R1 = mp_apply_q, L2>; // std::tuple -[endsect] +using R1 = mp_apply_q, L2>; +// R1 is std::tuple +``` +## mp_append -[section `mp_append`] template using mp_append = /*...*/; `mp_append` concatenates the lists in `L...` into a single list that has the same type as the first list. `mp_append<>` is an alias for `mp_list<>`. `mp_append, L2, ..., Ln>` is an alias for `L1`. - - using L1 = std::tuple; - using L2 = mp_list; - using L3 = std::pair; - using L4 = mp_list<>; - - using R1 = mp_append; // std::tuple -[endsect] +``` +using L1 = std::tuple; +using L2 = mp_list; +using L3 = std::pair; +using L4 = mp_list<>; + +using R1 = mp_append; // std::tuple +``` +## mp_replace_front -[section `mp_replace_front`] template using mp_replace_front = /*...*/; `mp_replace_front` replaces the first element of the list `L` with `T`. That is, `mp_replace_front, T>` is @@ -184,21 +192,21 @@ an alias for `L`. using L1 = std::pair; using R1 = mp_replace_front; // std::pair - + using L2 = std::tuple; using R2 = mp_replace_front; // std::tuple - + using L3 = mp_list; using R3 = mp_replace_front; // mp_list; -[endsect] -[section `mp_replace_first`] +## mp_replace_first + template using mp_replace_first = mp_replace_front; `mp_replace_first` is another name for `mp_replace_front`. -[endsect] -[section `mp_replace_second`] +## mp_replace_second + template using mp_replace_second = /*...*/; `mp_replace_second` replaces the second element of the list `L` with `T`. That is, `mp_replace_second, T>` @@ -206,15 +214,15 @@ is an alias for `L`. using L1 = std::pair; using R1 = mp_replace_second; // std::pair - + using L2 = std::tuple; using R2 = mp_replace_second; // std::tuple - + using L3 = mp_list; using R3 = mp_replace_second; // mp_list; -[endsect] -[section `mp_replace_third`] +## mp_replace_third + template using mp_replace_third = /*...*/; `mp_replace_third` replaces the third element of the list `L` with `T`. That is, `mp_replace_third, T>` @@ -222,9 +230,6 @@ is an alias for `L`. using L1 = std::tuple; using R1 = mp_replace_third; // std::tuple - + using L2 = mp_list; using R2 = mp_replace_third; // mp_list; -[endsect] - -[endsect:list] diff --git a/doc/mp11/map.qbk b/doc/mp11/map.adoc similarity index 72% rename from doc/mp11/map.qbk rename to doc/mp11/map.adoc index fad9dfd..96da55c 100644 --- a/doc/mp11/map.qbk +++ b/doc/mp11/map.adoc @@ -1,51 +1,54 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:map Map Operations, ``] +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#map] +# Map Operations, +:toc: +:toc-title: +:idprefix: A map is a list of lists, the inner lists having at least one element (the key.) The keys of the map must be unique. -[section `mp_map_find`] +## mp_map_find + template using mp_map_find = /*...*/; `mp_map_find` is an alias for the element of the map `M` with a key `K`, or for `void`, if there is no such element. -[endsect] -[section `mp_map_contains`] +## mp_map_contains + template using mp_map_contains = mp_not, void>>; `mp_map_contains` is `mp_true` if the map `M` contains an element with a key `K`, `mp_false` otherwise. -[endsect] -[section `mp_map_insert`] +## mp_map_insert + template using mp_map_insert = mp_if< mp_map_contains>, M, mp_push_back >; Inserts the element `T` into the map `M`, if an element with a key `mp_first` is not already in `M`. -[endsect] -[section `mp_map_replace`] +## mp_map_replace + template using mp_map_replace = /*...*/; If the map `M` does not contain an element with a key `mp_first`, inserts it (using `mp_push_back`); otherwise, replaces the existing element with `T`. -[endsect] -[section `mp_map_update`] +## mp_map_update + template class F> using mp_map_update = /*...*/; If the map `M` does not contain an element with a key `mp_first`, inserts it (using `mp_push_back`); otherwise, replaces the existing element `L` with `L>`. -[endsect] -[section `mp_map_erase`] +## mp_map_erase + template using mp_map_erase = /*...*/; If the map `M` contains an element with a key `K`, removes it. -[endsect] - -[endsect:map] diff --git a/doc/mp11/overview.qbk b/doc/mp11/overview.adoc similarity index 70% rename from doc/mp11/overview.qbk rename to doc/mp11/overview.adoc index 0686565..f7e8536 100644 --- a/doc/mp11/overview.qbk +++ b/doc/mp11/overview.adoc @@ -1,18 +1,20 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:overview Overview] +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#overview] +# Overview Mp11 is a C++11 metaprogramming library based on template aliases and variadic templates. It implements the approach outlined in the article -[@http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html Simple C++11 metaprogramming] and -[@http://pdimov.com/cpp2/simple_cxx11_metaprogramming_2.html its sequel]. Reading these -articles before proceeding with this documentation is highly recommended. +http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html["Simple {cpp} metaprogramming"] +and http://pdimov.com/cpp2/simple_cxx11_metaprogramming_2.html[its sequel]. Reading these +articles before proceeding with this documentation is _highly_ recommended. The general principles upon which Mp11 is built are that algorithms and metafunctions are template aliases of the form `F` and data structures are lists of the form `L`, @@ -30,5 +32,3 @@ gives us `std::tuple`, but we can also apply `mp_list` to the same using R = mp_transform>; and get `std::tuple, mp_list>`. - -[endsect:overview] diff --git a/doc/mp11/reference.adoc b/doc/mp11/reference.adoc new file mode 100644 index 0000000..113b0bd --- /dev/null +++ b/doc/mp11/reference.adoc @@ -0,0 +1,40 @@ +//// +Copyright 2017 Peter Dimov + +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#reference] +# Reference +:toc: +:toc-title: +:idprefix: + +The contents of the library are in namespace `boost::mp11`. + +:leveloffset: +1 + +include::integral.adoc[] + +include::list.adoc[] + +include::utility.adoc[] + +include::algorithm.adoc[] + +include::set.adoc[] + +include::map.adoc[] + +include::function.adoc[] + +include::bind.adoc[] + +include::integer_sequence.adoc[] + +include::tuple_for_each.adoc[] + +:leveloffset: -1 diff --git a/doc/mp11/set.qbk b/doc/mp11/set.adoc similarity index 60% rename from doc/mp11/set.qbk rename to doc/mp11/set.adoc index 3964d60..e8d708f 100644 --- a/doc/mp11/set.qbk +++ b/doc/mp11/set.adoc @@ -1,31 +1,34 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:set Set Operations, ``] +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#set] +# Set Operations, +:toc: +:toc-title: +:idprefix: A set is a list whose elements are unique. -[section `mp_set_contains`] +## mp_set_contains + template using mp_set_contains = /*...*/; `mp_set_contains` is `mp_true` if the type `V` is an element of the set `S`, `mp_false` otherwise. -[endsect] -[section `mp_set_push_back`] +## mp_set_push_back + template using mp_set_push_back = /*...*/; For each `T1` in `T...`, `mp_set_push_back` appends `T1` to the end of `S` if it's not already an element of `S`. -[endsect] -[section `mp_set_push_front`] +## mp_set_push_front + template using mp_set_push_front = /*...*/; `mp_set_push_front` inserts at the front of `S` those elements of `T...` for which `S` does not already contain the same type. -[endsect] - -[endsect:set] diff --git a/doc/mp11/tuple_for_each.adoc b/doc/mp11/tuple_for_each.adoc new file mode 100644 index 0000000..52afd04 --- /dev/null +++ b/doc/mp11/tuple_for_each.adoc @@ -0,0 +1,21 @@ +//// +Copyright 2017 Peter Dimov + +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#tuple_for_each] +# A "for each" algorithm for tuple-like types, +:idprefix: + +## tuple_for_each(tp, f) + + template constexpr F tuple_for_each(Tp&& tp, F&& f); + +`tuple_for_each(tp, f)` applies the function object `f` to each element of `tp` by evaluating the +expression `f(std::get(std::forward(tp)))` for `J` in 0..`N-1`, where `N` is `std::tuple_size::type>::value`. + +Returns `std::forward(f)`. diff --git a/doc/mp11/tuple_for_each.qbk b/doc/mp11/tuple_for_each.qbk deleted file mode 100644 index 9ba4c5b..0000000 --- a/doc/mp11/tuple_for_each.qbk +++ /dev/null @@ -1,20 +0,0 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] - -[section:tuple_for_each A "for each" algorithm for tuple-like types, ``] - -[section `tuple_for_each(tp, f)`] - template constexpr F tuple_for_each(Tp&& tp, F&& f); - -`tuple_for_each(tp, f)` applies the function object `f` to each element of `tp` by evaluating the -expression `f(std::get(std::forward(tp)))` for `J` in 0..`N-1`, where `N` is `std::tuple_size::type>::value`. - -Returns `std::forward(f)`. -[endsect] - -[endsect:tuple_for_each] diff --git a/doc/mp11/utility.qbk b/doc/mp11/utility.adoc similarity index 75% rename from doc/mp11/utility.qbk rename to doc/mp11/utility.adoc index 13b6f80..a0ac9ba 100644 --- a/doc/mp11/utility.qbk +++ b/doc/mp11/utility.adoc @@ -1,29 +1,35 @@ -[/ - / Copyright 2017 Peter Dimov - / - / Distributed under the Boost Software License, Version 1.0. (See - / accompanying file LICENSE_1_0.txt or copy at - / http://www.boost.org/LICENSE_1_0.txt) - /] +//// +Copyright 2017 Peter Dimov -[section:utility Utility Components, ``] +Distributed under the Boost Software License, Version 1.0. + +See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt +//// + +[#utility] +# Utility Components, +:toc: +:toc-title: +:idprefix: + +## mp_identity -[section `mp_identity`] template struct mp_identity { using type = T; }; -[endsect] -[section `mp_identity_t`] +## mp_identity_t + template using mp_identity_t = T; -[endsect] -[section `mp_inherit`] +## mp_inherit + template struct mp_inherit: T... {}; -[endsect] -[section `mp_if_c`] +## mp_if_c + template using mp_if_c = /*...*/; `mp_if_c` is an alias for `T`. `mp_if_c` is an alias for `E`. Otherwise, the result is a substitution failure. @@ -32,59 +38,56 @@ using R2 = mp_if_c; // void template using void_if_5 = mp_if_c; // `void` when `I::value` is 5, substitution failure otherwise -[endsect] -[section `mp_if`] +## mp_if + template using mp_if = mp_if_c(C::value), T, E...>; Like `mp_if_c`, but the first argument is a type. -[endsect] -[section `mp_eval_if_c`] +## mp_eval_if_c + template class F, class... U> using mp_eval_if_c = /*...*/; `mp_eval_if_c` is an alias for `T` when `C` is `true`, for `F` otherwise. Its purpose is to avoid evaluating `F` when the condition is `true` as it may not be valid in this case. -[endsect] -[section `mp_eval_if`] +## mp_eval_if + template class F, class... U> using mp_eval_if = mp_eval_if_c(C::value), T, F, U...>; Like `mp_eval_if_c`, but the first argument is a type. -[endsect] -[section `mp_eval_if_q`] +## mp_eval_if_q + template using mp_eval_if_q = mp_eval_if; Like `mp_eval_if`, but takes a quoted metafunction. -[endsect] -[section `mp_valid`] +## mp_valid + template class F, class... T> using mp_valid = /*...*/; `mp_valid` is an alias for `mp_true` when `F` is a valid expression, for `mp_false` otherwise. -[endsect] -[section `mp_defer`] +## mp_defer + template class F, class... T> using mp_defer = /*...*/; When `mp_valid` is `mp_true`, `mp_defer` is a struct with a nested type `type` which is an alias for `F`. Otherwise, `mp_defer` is an empty struct. -[endsect] -[section `mp_quote`] +## mp_quote + template class F> struct mp_quote { template using fn = F; }; `mp_quote` transforms the template `F` into a type with a nested template `fn` such that `fn` returns `F`. -[endsect] -[section `mp_invoke`] +## mp_invoke + template using mp_invoke = typename Q::template fn; `mp_invoke` evaluates the nested template `fn` of a quoted metafunction. `mp_invoke, T...>` returns `F`. -[endsect] - -[endsect:utility]