1
0
forked from boostorg/mp11

Merge branch 'feature/asciidoc' into develop

This commit is contained in:
Peter Dimov
2017-06-07 00:44:50 +03:00
23 changed files with 3653 additions and 3885 deletions

View File

@@ -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).

26
doc/Jamfile Normal file
View File

@@ -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 : <location>html ;
pdf mp11.pdf : mp11.adoc ;
explicit mp11.pdf ;
install pdf_ : mp11.pdf : <location>pdf ;
explicit pdf_ ;
###############################################################################
alias boostdoc ;
explicit boostdoc ;
alias boostrelease ;
explicit boostrelease ;

View File

@@ -1,41 +0,0 @@
# Copyright (c) 2002 Douglas Gregor <doug.gregor -at- gmail.com>
# 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 : <quickbook-strict-mode>on ;
boostbook standalone_mp11
:
mp11_
:
<xsl:param>boost.root=../../../..
# File name of HTML output:
<xsl:param>root.filename=mp11
# How far down we chunk nested sections, basically all of them:
<xsl:param>chunk.section.depth=0
# Don't put the first section on the same page as the TOC:
<xsl:param>chunk.first.sections=0
# How far down sections get TOC's
<xsl:param>toc.section.depth=3
# Max depth in each TOC:
<xsl:param>toc.max.depth=3
# How far down we go with TOC's
<xsl:param>generate.section.toc.level=0
<xsl:param>generate.manifest=0
<xsl:param>html.stylesheet=../css/boostbook.css
;
###############################################################################
alias boostdoc ;
explicit boostdoc ;
alias boostrelease : standalone_mp11 ;
explicit boostrelease ;

50
doc/asciidoctor.jam Normal file
View File

@@ -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)
}

View File

@@ -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 */

File diff suppressed because it is too large Load Diff

34
doc/mp11.adoc Normal file
View File

@@ -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].

View File

@@ -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 '''<simplesect><title>'''[title]'''</title>''']]
[template endsimplesect[]
[block '''</simplesect>''']]
[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]

View File

@@ -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, `<boost/mp11/algorithm.hpp>`]
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, <boost/mp11/algorithm.hpp>
:toc:
:toc-title:
:idprefix:
## mp_assign<L1, L2>
[section `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`.
[endsect]
[section `mp_clear<L>`]
## 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`.
[endsect]
[section `mp_transform<F, 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>...>`.
[endsect]
[section `mp_transform_q<Q, L...>`]
## 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.
[endsect]
[section `mp_transform_if<P, F, L...>`]
## 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`.
[endsect]
[section `mp_transform_if_q<Qp, Qf, L...>`]
## 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.
[endsect]
[section `mp_fill<L, V>`]
## 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.
[endsect]
[section `mp_count<L, V>`]
## 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`.
[endsect]
[section `mp_count_if<L, P>`]
## 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`.
[endsect]
[section `mp_contains<L, V>`]
## 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.
[endsect]
[section `mp_repeat_c<L, N>`]
## 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`.
[endsect]
[section `mp_repeat<L, N>`]
## 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.
[endsect]
[section `mp_product<F, L...>`]
## 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`.
[endsect]
[section `mp_product_q<Q, L...>`]
## 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.
[endsect]
[section `mp_drop_c<L, N>`]
## 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.
[endsect]
[section `mp_drop<L, N>`]
## 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.
[endsect]
[section `mp_iota_c<N>`]
## 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>>`.
[endsect]
[section `mp_iota<N>`]
## 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`.
[endsect]
[section `mp_at_c<L, I>`]
## 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.
[endsect]
[section `mp_at<L, I>`]
## 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.
[endsect]
[section `mp_take_c<L, N>`]
## 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`.
[endsect]
[section `mp_take<L, N>`]
## 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.
[endsect]
[section `mp_insert_c<L, I, T...>`]
## 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).
[endsect]
[section `mp_insert<L, I, T...>`]
## 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`.
[endsect]
[section `mp_erase_c<L, I, J>`]
## 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).
[endsect]
[section `mp_erase<L, I, J>`]
## 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`.
[endsect]
[section `mp_replace<L, V, W>`]
## 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.
[endsect]
[section `mp_replace_if<L, P, W>`]
## 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.
[endsect]
[section `mp_replace_at_c<L, I, W>`]
## 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.
[endsect]
[section `mp_replace_at<L, I, W>`]
## 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.
[endsect]
[section `mp_copy_if<L, P>`]
## 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.
[endsect]
[section `mp_remove<L, V>`]
## mp_remove<L, V>
template<class L, class V> using mp_remove = /*...*/;
Removes all `V` elements of `L` and returns the result.
[endsect]
[section `mp_remove_if<L, P>`]
## 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.
[endsect]
[section `mp_partition<L, P>`]
## 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...>>`.
[endsect]
[section `mp_sort<L, P>`]
## 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>>`.
[endsect]
[section `mp_find<L, V>`]
## 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>`.
[endsect]
[section `mp_find_if<L, P>`]
## 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>`.
[endsect]
[section `mp_reverse<L>`]
## mp_reverse<L>
template<class L> using mp_reverse = /*...*/;
`mp_reverse<L<T1, T2, ..., Tn>>` is `L<Tn, ..., T2, T1>`.
[endsect]
[section `mp_fold<L, V, F>`]
## 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.
[endsect]
[section `mp_reverse_fold<L, V, F>`]
## 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.
[endsect]
[section `mp_unique<L>`]
## 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.
[endsect]
[section `mp_all_of<L, P>`]
## 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`.
[endsect]
[section `mp_none_of<L, P>`]
## 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`.
[endsect]
[section `mp_any_of<L, P>`]
## 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`.
[endsect]
[section `mp_for_each<L>(f)`]
## 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)`.
[endsect]
[section `mp_with_index<N>(i, 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`.
@@ -297,6 +303,3 @@ Returns `std::forward<F>(f)`.
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)`.
[endsect]
[endsect:algorithm]

View File

@@ -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, `<boost/mp11/bind.hpp>`]
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, <boost/mp11/bind.hpp>
:toc:
:toc-title:
:idprefix:
## mp_arg<I>
[section `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...`.
[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<F, T...>`]
## 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
@@ -36,36 +42,33 @@ template `fn<U...>` returns `F<V...>`, 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<F, int, _2, mp_bind<G, _1>>::fn<float, void>` is `F<int, void, G<float>>`.
[endsect]
[section `mp_bind_q<Q, T...>`]
## 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.
[endsect]
[section `mp_bind_front<F, T...>`]
## 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...>`.
[endsect]
[section `mp_bind_front_q<Q, T...>`]
## 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.
[endsect]
[section `mp_bind_back<F, T...>`]
## 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...>`.
[endsect]
[section `mp_bind_back_q<Q, 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.
[endsect]
[endsect:bind]

View File

@@ -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 '''&mdash;''' usually but not necessarily variadic '''&mdash;''' 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<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`,
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
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,
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 _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<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]>>;
[endsect:definitions]

View File

@@ -1,24 +1,33 @@
[/
/ 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<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;
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() );
@@ -26,7 +35,7 @@ of `T` and `U`, so we write the function
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()
@@ -40,7 +49,7 @@ 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 <boost/mp11.hpp>
#include <boost/core/demangle.hpp>
#include <type_traits>
@@ -55,7 +64,9 @@ how we can leverage Mp11 to automate the task:
}
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 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& )
{
@@ -63,7 +74,8 @@ how we can leverage Mp11 to automate the task:
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;
<< name<T1>() << " + " << name<T2>() << " -> " << name<T3>()
<< ", result: " << name<T4>() << std::endl;
}
int main()
@@ -71,7 +83,7 @@ how we can leverage Mp11 to automate the task:
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
@@ -86,7 +98,7 @@ 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
@@ -95,7 +107,8 @@ a templated `operator()` and pass that to `tuple_for_each` directly:
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;
<< name<T1>() << " + " << name<T2>() << " -> " << name<T3>()
<< ", result: " << name<T4>() << std::endl;
}
};
@@ -104,10 +117,8 @@ a templated `operator()` and pass that to `tuple_for_each` directly:
using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
tuple_for_each( mp_product<mp_list, L, L>(), test_result() );
}
[endsect]
[section Writing `common_type` specializations]
```
## 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<class... T> using common_type_t =
typename std::common_type<T...>::type; // standard in C++14
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>;
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...>>
template<class... T1, class... T2>
struct common_type<std::tuple<T1...>, std::tuple<T2...>>:
mp_defer<common_tuple, std::tuple<T1...>, std::tuple<T2...>>
{
};
} // 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/.
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,30 +161,31 @@ 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<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 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
{
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...>>
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...>>
{
};
} // 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`.
[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<class L> using F = mp_iota<mp_size<L>>;
template<class R, class...Is, class... Ks, class Tp>
@@ -203,31 +219,31 @@ implementation of the standard function `tuple_cat`, with the end result given b
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;
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;
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 };
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
@@ -250,7 +266,7 @@ primitive that is inexplicably missing from the standard library:
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 )
@@ -262,7 +278,7 @@ and then by using `remove_cv_ref<Tp>` in place of `typename std::remove_referenc
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,
@@ -273,10 +289,13 @@ 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, 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>>>;
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`,
@@ -287,10 +306,11 @@ as `L1` (an `mp_list`) with contents `tuple_element<T, mp_size_t<0>>`, `tuple_el
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>>>;
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>>;
template<class R, class...Is, class... Ks, class Tp>
@@ -302,8 +322,11 @@ With all these fixes applied, our fully operational `tuple_cat` now looks like t
template<class T> using remove_cv_ref = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
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>>>;
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>>>;
template<class... Tp,
class R = mp_append<std::tuple<>, from_tuple_like<remove_cv_ref<Tp>>...>>
@@ -330,14 +353,12 @@ With all these fixes applied, our fully operational `tuple_cat` now looks like t
return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) );
}
[endsect]
[section Computing Return Types]
```
## 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<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 )... );
}
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.
@@ -383,10 +407,10 @@ 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<mp_product<Qret<F>::template fn, std::remove_reference_t<V>...>>;
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>
@@ -404,7 +428,10 @@ and we're done:
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 )... );
return std::visit( [&]( auto&&... x )
{ return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); },
std::forward<V>( v )... );
}
template<class T> std::string name()
@@ -414,22 +441,23 @@ and we're done:
int main()
{
std::variant<signed char, unsigned char, signed short, unsigned short, int, unsigned> v1( 1 );
std::variant<signed char, unsigned char, signed short, unsigned short,
int, unsigned> v1( 1 );
std::cout << "(" << name<decltype(v1)>() << ")v1: ";
std::visit( []( auto const& x ){ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v1 );
std::visit( []( auto const& x )
{ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v1 );
std::variant<int, float, double> v2( 2.0f );
std::cout << "(" << name<decltype(v2)>() << ")v2: ";
std::visit( []( auto const& x ){ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v2 );
std::visit( []( auto const& x )
{ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v2 );
auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
std::cout << "(" << name<decltype(v3)>() << ")v3: ";
std::visit( []( auto const& x ){ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v3 );
std::visit( []( auto const& x )
{ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v3 );
}
[endsect]
[endsect:examples]
```

View File

@@ -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, `<boost/mp11/function.hpp>`]
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, <boost/mp11/function.hpp>
:toc:
:toc-title:
:idprefix:
## mp_void<T...>
[section `mp_void<T...>`]
template<class... T> using mp_void = void;
Same as `std::void_t` from C++17.
[endsect]
[section `mp_and<T...>`]
## 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`
@@ -25,9 +31,9 @@ returns `mp_true`. `mp_and<>` is `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 (!)
[endsect]
[section `mp_all<T...>`]
## 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
@@ -39,9 +45,9 @@ mask substitution failures as `mp_and` does.
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
[endsect]
[section `mp_or<T...>`]
## 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`
@@ -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>; // 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
[endsect]
[section `mp_any<T...>`]
## 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
@@ -63,19 +69,16 @@ returns `mp_true`. If all results are `mp_false`, returns `mp_false`. `mp_or<>`
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
[endsect]
[section `mp_same<T...>`]
## 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`.
[endsect]
[section `mp_plus<T...>`]
## 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>`.
[endsect]
[endsect:function]

View File

@@ -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, `<boost/mp11/integer_sequence.hpp>`]
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, <boost/mp11/integer_sequence.hpp>
:toc:
:toc-title:
:idprefix:
## integer_sequence<T, I...>
[section `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`.
[endsect]
[section `make_integer_sequence<T, N>`]
## 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`.
[endsect]
[section `index_sequence<I...>`]
## 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`.
[endsect]
[section `make_index_sequence<N>`]
## 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`.
[endsect]
[section `index_sequence_for<T...>`]
## 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`.
[endsect]
[endsect:integer_sequence]

View File

@@ -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, `<boost/mp11/integral.hpp>`]
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, <boost/mp11/integral.hpp>
:toc:
:toc-title:
:idprefix:
For an Mp11 integral constant type `T`, `T::value` is an integral constant in the C++ sense.
[section `mp_bool<B>`]
## mp_bool<B>
template<bool B> using mp_bool = std::integral_constant<bool, B>;
[endsect]
[section `mp_true`]
## mp_true
using mp_true = mp_bool<true>;
[endsect]
[section `mp_false`]
## mp_false
using mp_false = mp_bool<false>;
[endsect]
[section `mp_to_bool<T>`]
## mp_to_bool<T>
template<class T> using mp_to_bool = mp_bool<static_cast<bool>(T::value)>;
[endsect]
[section `mp_not<T>`]
## mp_not<T>
template<class T> using mp_not = mp_bool< !T::value >;
[endsect]
[section `mp_int<I>`]
## mp_int<I>
template<int I> using mp_int = std::integral_constant<int, I>;
[endsect]
[section `mp_size_t<N>`]
## mp_size_t<N>
template<std::size_t N> using mp_size_t = std::integral_constant<std::size_t, N>;
[endsect]
[endsect:integral]

View File

@@ -1,44 +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)
/]
////
Copyright 2017 Peter Dimov
[section:list List Operations, `<boost/mp11/list.hpp>`]
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, <boost/mp11/list.hpp>
:toc:
:toc-title:
:idprefix:
## mp_list<T...>
[section `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.
[endsect]
[section `mp_size<L>`]
## 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 R1 = mp_size<L1>; // mp_size_t\<0>
using L2 = std::pair<int, int>;
using R2 = mp_size<L2>; // mp_size_t<2>
using R2 = mp_size<L2>; // mp_size_t\<2>
using L3 = std::tuple<float>;
using R3 = mp_size<L3>; // mp_size_t<1>
[endsect]
using R3 = mp_size<L3>; // mp_size_t\<1>
## mp_empty<L>
[section `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.
[endsect]
[section `mp_front<L>`]
## 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`.
@@ -51,9 +57,9 @@ the list.
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_front<L3>; // char[1]
[endsect]
[section `mp_pop_front<L>`]
## 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...>`.
@@ -63,21 +69,21 @@ the list.
using L2 = mp_list<void>;
using R2 = mp_pop_front<L2>; // mp_list<>
[endsect]
[section `mp_first<L>`]
## mp_first<L>
template<class L> using mp_first = mp_front<L>;
`mp_first` is another name for `mp_front`.
[endsect]
[section `mp_rest<L>`]
## mp_rest<L>
template<class L> using mp_rest = mp_pop_front<L>;
`mp_rest` is another name for `mp_pop_front`.
[endsect]
[section `mp_second<L>`]
## 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`.
@@ -90,9 +96,9 @@ the list.
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_second<L3>; // char[2]
[endsect]
[section `mp_third<L>`]
## 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`.
@@ -102,9 +108,9 @@ the list.
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
using R2 = mp_third<L2>; // char[3]
[endsect]
[section `mp_push_front<L, T...>`]
## 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...>`
@@ -115,9 +121,9 @@ is an alias for `L<T..., U...>`.
using L2 = mp_list<void>;
using R2 = mp_push_front<L2, char[1], char[2]>; // mp_list<char[1], char[2], void>
[endsect]
[section `mp_push_back<L, T...>`]
## 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...>`
@@ -128,9 +134,9 @@ is an alias for `L<U..., T...>`.
using L2 = mp_list<void>;
using R2 = mp_push_back<L2, char[1], char[2]>; // mp_list<void, char[1], char[2]>
[endsect]
[section `mp_rename<L, Y>`]
## 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...>`.
@@ -140,9 +146,9 @@ is an alias for `L<U..., T...>`.
using L2 = std::tuple<void>;
using R2 = mp_rename<L2, mp_list>; // mp_list<void>
[endsect]
[section `mp_apply<F, L>`]
## 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...>`.
@@ -150,33 +156,35 @@ is an alias for `L<U..., T...>`.
using L1 = std::pair<double, long double>;
using R1 = mp_apply<std::is_same, L1>; // std::is_same<double, long double>
[endsect]
[section `mp_apply_q<Q, L>`]
## 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 R1 = mp_apply_q<mp_bind_front<mp_push_back, L1>, L2>; // std::tuple<double, long double, int, long>
[endsect]
[section `mp_append<L...>`]
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<>;
using R1 = mp_append<L1, L2, L3, L4>; // std::tuple<double, long double, int, short, long>
[endsect]
```
## mp_replace_front<L, T>
[section `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
@@ -190,15 +198,15 @@ an alias for `L<T, U...>`.
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]>;
[endsect]
[section `mp_replace_first<L, T>`]
## 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`.
[endsect]
[section `mp_replace_second<L, T>`]
## 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>`
@@ -212,9 +220,9 @@ is an alias for `L<U1, T, U...>`.
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]>;
[endsect]
[section `mp_replace_third<L, T>`]
## 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>`
@@ -225,6 +233,3 @@ is an alias for `L<U1, U2, T, U...>`.
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]>;
[endsect]
[endsect:list]

View File

@@ -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, `<boost/mp11/map.hpp>`]
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, <boost/mp11/map.hpp>
: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<M, K>`]
## 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.
[endsect]
[section `mp_map_contains<M, K>`]
## 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.
[endsect]
[section `mp_map_insert<M, T>`]
## 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`.
[endsect]
[section `mp_map_replace<M, T>`]
## 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`.
[endsect]
[section `mp_map_update<M, T, F>`]
## 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...>>`.
[endsect]
[section `mp_map_erase<M, K>`]
## 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.
[endsect]
[endsect:map]

View File

@@ -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<T...>` and data structures are lists of the form `L<T...>`,
@@ -30,5 +32,3 @@ gives us `std::tuple<int*, float*>`, but we can also apply `mp_list` to the same
using R = mp_transform<mp_list, std::tuple<int, float>>;
and get `std::tuple<mp_list<int>, mp_list<float>>`.
[endsect:overview]

40
doc/mp11/reference.adoc Normal file
View File

@@ -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

View File

@@ -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, `<boost/mp11/set.hpp>`]
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, <boost/mp11/set.hpp>
:toc:
:toc-title:
:idprefix:
A set is a list whose elements are unique.
[section `mp_set_contains<S, V>`]
## 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.
[endsect]
[section `mp_set_push_back<S, T...>`]
## 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`.
[endsect]
[section `mp_set_push_front<S, T...>`]
## 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.
[endsect]
[endsect:set]

View File

@@ -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, <boost/mp11/tuple_for_each.hpp>
:idprefix:
## 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)`.

View File

@@ -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, `<boost/mp11/tuple_for_each.hpp>`]
[section `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)`.
[endsect]
[endsect:tuple_for_each]

View File

@@ -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, `<boost/mp11/utility.hpp>`]
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, <boost/mp11/utility.hpp>
:toc:
:toc-title:
:idprefix:
## mp_identity<T>
[section `mp_identity<T>`]
template<class T> struct mp_identity
{
using type = T;
};
[endsect]
[section `mp_identity_t<T>`]
## mp_identity_t<T>
template<class T> using mp_identity_t = T;
[endsect]
[section `mp_inherit<T...>`]
## mp_inherit<T...>
template<class... T> struct mp_inherit: T... {};
[endsect]
[section `mp_if_c<C, T, E...>`]
## 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.
@@ -32,59 +38,56 @@
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
[endsect]
[section `mp_if<C, T, E...>`]
## 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.
[endsect]
[section `mp_eval_if_c<C, T, F, U...>`]
## 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.
[endsect]
[section `mp_eval_if<C, T, F, U...>`]
## 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.
[endsect]
[section `mp_eval_if_q<C, T, Q, U...>`]
## 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.
[endsect]
[section `mp_valid<F, T...>`]
## 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.
[endsect]
[section `mp_defer<F, T...>`]
## 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.
[endsect]
[section `mp_quote<F>`]
## 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...>`.
[endsect]
[section `mp_invoke<Q, 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...>`.
[endsect]
[endsect:utility]