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 * g++ 4.7 or later
* clang 3.5 or later * clang 3.5 or later
* Visual Studio 2013, 2015, 2017 * 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 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: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 = /*...*/; 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_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<>>; 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_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 = /*...*/; 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<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...>; template<class Q, class... L> using mp_transform_q = mp_transform<Q::template fn, L...>;
As `mp_transform`, but takes a quoted metafunction. 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 = /*...*/; 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 `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`. `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...>; 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. 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 = /*...*/; 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_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 = /*...*/; 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<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 = /*...*/; 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_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>>; 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_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 = /*...*/; 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_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 = /*...*/; 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. 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 = /*...*/; 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 `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`. 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`. 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...>; template<class Q, class... L> using mp_product_q = mp_product<Q::template fn, L...>;
As `mp_product`, but takes a quoted metafunction. 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 = /*...*/; 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_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 = /*...*/; 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. 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 = /*...*/; 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_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 = /*...*/; 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 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>>` `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`. 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 = /*...*/; 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_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 = /*...*/; 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. 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 = /*...*/; 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_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 = /*...*/; 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. 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...>>; 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). 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...>>; 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`. 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>>; 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). 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>>; 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`. 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 = /*...*/; template<class L, class V, class W> using mp_replace = /*...*/;
Replaces all `V` elements of `L` with `W` and returns the result. 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 = /*...*/; 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. 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 = /*...*/; 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. 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 = /*...*/; 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. 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 = /*...*/; 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. 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 = /*...*/; template<class L, class V> using mp_remove = /*...*/;
Removes all `V` elements of `L` and returns the result. 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 = /*...*/; 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. 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 = /*...*/; 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` `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...>>`. 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 = /*...*/; 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_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 = /*...*/; 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>`, `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>` 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>`. 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 = /*...*/; 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_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_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 = /*...*/; template<class L> using mp_reverse = /*...*/;
`mp_reverse<L<T1, T2, ..., Tn>>` is `L<Tn, ..., T2, T1>`. `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 = /*...*/; 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_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 = /*...*/; 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_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 = /*...*/; template<class L> using mp_unique = /*...*/;
`mp_unique<L>` returns a list of the same type as `L` with the duplicate elements removed. `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 >; 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_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 >; 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_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 >; 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_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); 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. `mp_for_each<L>(f)` calls `f` with `T()` for each element `T` of the list `L`, in order.
Returns `std::forward<F>(f)`. 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 ); 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`. `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 ); 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)`. Returns `mp_with_index<N::value>(i, f)`.
[endsect]
[endsect:algorithm]

View File

@@ -1,20 +1,26 @@
[/ ////
/ Copyright 2017 Peter Dimov 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: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; 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...`. `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 _1 = mp_arg<0>;
using _2 = mp_arg<1>; using _2 = mp_arg<1>;
using _3 = mp_arg<2>; using _3 = mp_arg<2>;
@@ -26,9 +32,9 @@
using _9 = mp_arg<8>; using _9 = mp_arg<8>;
`_1` to `_9` are placeholder types, the equivalent to the placeholders of `boost::bind`. `_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; 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 `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...`. 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>>`. 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...>; template<class Q, class... T> using mp_bind_q = mp_bind<Q::template fn, T...>;
As `mp_bind`, but takes a quoted metafunction. 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; 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<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...>; 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. 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; 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<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...>; 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. As `mp_bind_back`, but takes a quoted metafunction.
[endsect]
[endsect:bind]

View File

@@ -1,39 +1,39 @@
[/ ////
/ Copyright 2017 Peter Dimov 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: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>`. 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 `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...> using F1 = void;
template<class T> using F2 = T*; template<class T> using F2 = T*;
template<class... T> using F3 = std::integral_constant<std::size_t, sizeof...(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 Q1 { template<class...> using fn = void; };
struct Q2 { template<class T> using fn = T*; }; struct Q2 { template<class T> using fn = T*; };
struct Q3 { template<class... T> using fn = std::integral_constant<std::size_t, sizeof...(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 `std::integral_constant<int, 7>`, or
struct N { static int constexpr value = 2; }; 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 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]>>; using M2 = mp_list<mp_list<int, int*>, mp_list<float>, mp_list<char, char[1], char[2]>>;
[endsect:definitions]

View File

@@ -1,32 +1,41 @@
[/ ////
/ Copyright 2017 Peter Dimov 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: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>`: 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> 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`, 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 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 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>;
template<class T1, class T2> void test_result() std::cout << ( std::is_same<T3, T4>::value? "[PASS]": "[FAIL]" ) << std::endl;
{ }
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: and then need to call it a substantial number of times:
int main() 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 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: 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>
#include <boost/mp11.hpp> using namespace boost::mp11;
#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> std::string name() template<class T> using promote = typename std::common_type<T, int>::type;
{
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 =
template<class T, class U> using result = typename std::common_type<promote<T>, promote<U>>::type; typename std::common_type<promote<T>, promote<U>>::type;
template<class T1, class T2> void test_result( mp_list<T1, T2> const& ) template<class T1, class T2> void test_result( mp_list<T1, T2> const& )
{ {
using T3 = decltype( T1() + T2() ); using T3 = decltype( T1() + T2() );
using T4 = result<T1, T2>; using T4 = result<T1, T2>;
std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " ) 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()
{
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); } );
}
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? 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 `mp_product<F, L1, L2>` calls `F<T1, T2>` 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 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: a templated `operator()` and pass that to `tuple_for_each` directly:
```
struct test_result struct test_result
{
template<class T1, class T2> void operator()( mp_list<T1, T2> const& ) const
{ {
template<class T1, class T2> void operator()( mp_list<T1, T2> const& ) const using T3 = decltype( T1() + T2() );
{ using T4 = result<T1, T2>;
using T3 = decltype( T1() + T2() );
using T4 = result<T1, T2>;
std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " ) 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()
{
using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
tuple_for_each( mp_product<mp_list, L, L>(), test_result() );
} }
};
[endsect] int main()
{
[section Writing `common_type` specializations] 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 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 `?:` 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 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: 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: then specialize `common_type` to use it:
```
namespace std
{
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
{ ```
};
} // std
(There is no need to specialize `std::common_type` for more than two arguments - it takes care of synthesizing the appropriate semantics from (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 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...>>`, 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`, 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. 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. combined into their common type, and we take the union of the set of error types.
Therefore, 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
{
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
{ ```
};
} // 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 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 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` 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`. 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: 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 L> using F = mp_iota<mp_size<L>>; 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 R, class...Is, class... Ks, class Tp> template<class... Tp,
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp ) class R = mp_append<std::tuple<>, typename std::remove_reference<Tp>::type...>>
{ R tuple_cat( Tp &&... tp )
return R{ std::get<Ks::value>(std::get<Is::value>(tp))... }; {
} std::size_t const N = sizeof...(Tp);
template<class... Tp, // inner
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 using list1 = mp_list<mp_rename<typename std::remove_reference<Tp>::type, mp_list>...>;
using list2 = mp_iota_c<N>;
using list1 = mp_list<mp_rename<typename std::remove_reference<Tp>::type, mp_list>...>; using list3 = mp_transform<mp_fill, list1, list2>;
using list2 = mp_iota_c<N>;
using list3 = mp_transform<mp_fill, list1, list2>; using inner = mp_apply<mp_append, list3>;
using inner = mp_apply<mp_append, list3>; // outer
// outer using list4 = mp_transform<F, list1>;
using list4 = mp_transform<F, list1>; using outer = mp_apply<mp_append, list4>;
using outer = mp_apply<mp_append, list4>; //
//
return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) );
}
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, 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: 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;
std::tuple<std::unique_ptr<int>> t1; auto result = ::tuple_cat( std::move( t1 ), std::move( t2 ) );
std::tuple<std::unique_ptr<float>> t2; ```
auto result = ::tuple_cat( std::move( t1 ), std::move( t2 ) );
Trying to concatenate `const` tuples fails: Trying to concatenate `const` tuples fails:
```
std::tuple<int> const t1;
std::tuple<float> const t2;
std::tuple<int> const t1; auto result = ::tuple_cat( t1, t2 );
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 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 that support `tuple_size`, `tuple_element`, and `get`), while our implementation only works with `tuple` and
`pair`. `std::array`, for example, fails: `pair`. `std::array`, for example, fails:
```
std::array<int, 2> t1{ 1, 2 };
std::array<float, 3> t2{ 3.0f, 4.0f, 5.0f };
std::array<int, 2> t1{ 1, 2 }; auto result = ::tuple_cat( t1, t2 );
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 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>&&>`, 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 but `std::get<0>(tp)` still returns `unique_ptr<int>&`, 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<T>::type>::type; typename std::remove_reference<T>::type>::type;
and then by using `remove_cv_ref<Tp>` in place of `typename std::remove_reference<Tp>::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, // inner
class R = mp_append<std::tuple<>, remove_cv_ref<Tp>...>>
R tuple_cat( Tp &&... tp )
{
std::size_t const N = sizeof...(Tp);
// inner
using list1 = mp_list<mp_rename<remove_cv_ref<Tp>, mp_list>...>;
// ...
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, 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 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, 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, 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: ..., 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 =
template<class T> using from_tuple_like = mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>; 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>`.) (`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`, Remember that `mp_product<F, L1, L2>` 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<T, mp_size_t<0>>`, `tuple_el
For completeness's sake, here's another, more traditional way to achieve the same result: 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: 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 L> using F = mp_iota<mp_size<L>>; 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 R, class...Is, class... Ks, class Tp> template<class T> using remove_cv_ref = typename std::remove_cv<
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp ) typename std::remove_reference<T>::type>::type;
{
return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
}
template<class T> using remove_cv_ref = typename std::remove_cv< template<class T, class I> using tuple_element =
typename std::remove_reference<T>::type>::type; 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... Tp,
template<class T> using from_tuple_like = mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>; 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);
template<class... Tp, // inner
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);
// inner using list1 = mp_list<from_tuple_like<remove_cv_ref<Tp>>...>;
using list2 = mp_iota_c<N>;
using list1 = mp_list<from_tuple_like<remove_cv_ref<Tp>>...>; using list3 = mp_transform<mp_fill, list1, list2>;
using list2 = mp_iota_c<N>;
using list3 = mp_transform<mp_fill, list1, list2>; using inner = mp_apply<mp_append, list3>;
using inner = mp_apply<mp_append, list3>; // outer
// outer using list4 = mp_transform<F, list1>;
using list4 = mp_transform<F, list1>; using outer = mp_apply<mp_append, list4>;
using outer = mp_apply<mp_append, list4>; //
// return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) );
}
return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) ); ```
} ## Computing Return Types
[endsect]
[section Computing Return Types]
C++17 has a standard variant type, called `std::variant`. It also defines a function template 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. `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`, 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)`. `std::visit(f, v1, v2)` will call `f(1, 2.0f)`.
However, `std::visit` has one limitation: it cannot return a result unless all 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>`. 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`: 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 = /*...*/;
template<class F, class... V> auto rvisit( F&& f, V&&... v ) return std::visit( [&]( auto&&... x )
{ { return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); },
using R = /*...*/; 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 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 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. 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 `[]( 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, 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: and we're done:
```
#include <boost/mp11.hpp>
#include <boost/core/demangle.hpp>
#include <variant>
#include <type_traits>
#include <typeinfo>
#include <iostream>
#include <boost/mp11.hpp> using namespace boost::mp11;
#include <boost/core/demangle.hpp>
#include <variant>
#include <type_traits>
#include <typeinfo>
#include <iostream>
using namespace boost::mp11; template<class F> struct Qret
{
template<class... T> using fn = decltype( std::declval<F>()( std::declval<T>()... ) );
};
template<class F> struct Qret template<class F, class... V> auto rvisit( F&& f, V&&... v )
{ {
template<class... T> using fn = decltype( std::declval<F>()( std::declval<T>()... ) ); using R = mp_unique<mp_product_q<Qret<F>, std::remove_reference_t<V>...>>;
};
template<class F, class... V> auto rvisit( F&& f, V&&... v ) return std::visit( [&]( auto&&... x )
{ { return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); },
using R = mp_unique<mp_product_q<Qret<F>, std::remove_reference_t<V>...>>; 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() template<class T> std::string name()
{ {
return boost::core::demangle( typeid(T).name() ); return boost::core::demangle( typeid(T).name() );
} }
int main() 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::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::variant<int, float, double> v2( 2.0f );
std::cout << "(" << name<decltype(v2)>() << ")v2: "; 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 ); auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
std::cout << "(" << name<decltype(v3)>() << ")v3: "; 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 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: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; template<class... T> using mp_void = void;
Same as `std::void_t` from C++17. Same as `std::void_t` from C++17.
[endsect]
[section `mp_and<T...>`] ## mp_and<T...>
template<class... T> using mp_and = /*...*/; 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` `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 R2 = mp_and<mp_false, void>; // mp_false, void is not reached
using R3 = mp_and<mp_false, mp_false>; // mp_false using R3 = mp_and<mp_false, mp_false>; // mp_false
using R4 = mp_and<void, mp_true>; // 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 = /*...*/; 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_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 R2 = mp_and<mp_false, void>; // compile-time error
using R3 = mp_and<mp_false, mp_false>; // mp_false using R3 = mp_and<mp_false, mp_false>; // mp_false
using R4 = mp_and<void, mp_true>; // compile-time error using R4 = mp_and<void, mp_true>; // compile-time error
[endsect]
[section `mp_or<T...>`] ## mp_or<T...>
template<class... T> using mp_or = /*...*/; 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` `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 R2 = mp_or<mp_true, void>; // mp_true, void is not reached
using R3 = mp_or<mp_false, mp_false>; // mp_false using R3 = mp_or<mp_false, mp_false>; // mp_false
using R4 = mp_or<void, mp_true>; // compile-time error using R4 = mp_or<void, mp_true>; // compile-time error
[endsect]
[section `mp_any<T...>`] ## mp_any<T...>
template<class... T> using mp_any = /*...*/; 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_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 R2 = mp_any<mp_true, void>; // compile-time error
using R3 = mp_any<mp_false, mp_false>; // mp_false using R3 = mp_any<mp_false, mp_false>; // mp_false
using R4 = mp_any<void, mp_true>; // compile-time error using R4 = mp_any<void, mp_true>; // compile-time error
[endsect]
[section `mp_same<T...>`] ## mp_same<T...>
template<class... T> using mp_same = /*...*/; 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_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 = /*...*/; 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<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>`. `mp_plus<>` is `mp_int<0>`.
[endsect]
[endsect:function]

View File

@@ -1,43 +1,46 @@
[/ ////
/ Copyright 2017 Peter Dimov 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: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 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`. `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 = /*...*/; 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`. `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...>; 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`. `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>; 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`. `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)>; 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`. `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 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: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. 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>; template<bool B> using mp_bool = std::integral_constant<bool, B>;
[endsect]
[section `mp_true`] ## mp_true
using mp_true = mp_bool<true>; using mp_true = mp_bool<true>;
[endsect]
[section `mp_false`] ## mp_false
using mp_false = mp_bool<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)>; 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 >; 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>; 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>; template<std::size_t N> using mp_size_t = std::integral_constant<std::size_t, N>;
[endsect]
[endsect:integral]

View File

@@ -1,110 +1,116 @@
[/ ////
/ Copyright 2017 Peter Dimov 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: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 {}; 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 `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 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. the list.
[endsect]
[section `mp_size<L>`] ## mp_size<L>
template<class L> using mp_size = /*...*/; 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<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)>`. `mp_size_t<sizeof...(T)>`.
using L1 = mp_list<>; 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 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 L3 = std::tuple<float>;
using R3 = mp_size<L3>; // mp_size_t<1> using R3 = mp_size<L3>; // mp_size_t\<1>
[endsect]
## mp_empty<L>
[section `mp_empty<L>`]
template<class L> using mp_empty = mp_bool<mp_size<L>::value == 0>; 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_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 = /*...*/; 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`. `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 L1 = std::pair<int, float>;
using R1 = mp_front<L1>; // int using R1 = mp_front<L1>; // int
using L2 = std::tuple<float, double, long double>; using L2 = std::tuple<float, double, long double>;
using R2 = mp_front<L2>; // float using R2 = mp_front<L2>; // float
using L3 = mp_list<char[1], char[2], char[3], char[4]>; using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_front<L3>; // char[1] using R3 = mp_front<L3>; // char[1]
[endsect]
[section `mp_pop_front<L>`] ## mp_pop_front<L>
template<class L> using mp_pop_front = /*...*/; 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...>`. `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 L1 = std::tuple<float, double, long double>;
using R1 = mp_pop_front<L1>; // std::tuple<double, long double> using R1 = mp_pop_front<L1>; // std::tuple<double, long double>
using L2 = mp_list<void>; using L2 = mp_list<void>;
using R2 = mp_pop_front<L2>; // mp_list<> 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>; template<class L> using mp_first = mp_front<L>;
`mp_first` is another name for `mp_front`. `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>; template<class L> using mp_rest = mp_pop_front<L>;
`mp_rest` is another name for `mp_pop_front`. `mp_rest` is another name for `mp_pop_front`.
[endsect]
[section `mp_second<L>`] ## mp_second<L>
template<class L> using mp_second = /*...*/; 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`. `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 L1 = std::pair<int, float>;
using R1 = mp_second<L1>; // float using R1 = mp_second<L1>; // float
using L2 = std::tuple<float, double, long double>; using L2 = std::tuple<float, double, long double>;
using R2 = mp_second<L2>; // double using R2 = mp_second<L2>; // double
using L3 = mp_list<char[1], char[2], char[3], char[4]>; using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_second<L3>; // char[2] using R3 = mp_second<L3>; // char[2]
[endsect]
[section `mp_third<L>`] ## mp_third<L>
template<class L> using mp_third = /*...*/; 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`. `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 L1 = std::tuple<float, double, long double>;
using R1 = mp_third<L1>; // long double using R1 = mp_third<L1>; // long double
using L2 = mp_list<char[1], char[2], char[3], char[4]>; using L2 = mp_list<char[1], char[2], char[3], char[4]>;
using R2 = mp_third<L2>; // char[3] 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 = /*...*/; 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...>` `mp_push_front<L, T...>` inserts the elements `T...` at the front of the list `L`. That is, `mp_push_front<L<U...>, T...>`
@@ -112,12 +118,12 @@ is an alias for `L<T..., U...>`.
using L1 = std::tuple<double, long double>; using L1 = std::tuple<double, long double>;
using R1 = mp_push_front<L1, float>; // std::tuple<float, double, long double> using R1 = mp_push_front<L1, float>; // std::tuple<float, double, long double>
using L2 = mp_list<void>; using L2 = mp_list<void>;
using R2 = mp_push_front<L2, char[1], char[2]>; // mp_list<char[1], char[2], 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 = /*...*/; 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...>` `mp_push_back<L, T...>` inserts the elements `T...` at the back of the list `L`. That is, `mp_push_back<L<U...>, T...>`
@@ -125,24 +131,24 @@ is an alias for `L<U..., T...>`.
using L1 = std::tuple<double, long double>; using L1 = std::tuple<double, long double>;
using R1 = mp_push_back<L1, float>; // std::tuple<double, long double, float> using R1 = mp_push_back<L1, float>; // std::tuple<double, long double, float>
using L2 = mp_list<void>; using L2 = mp_list<void>;
using R2 = mp_push_back<L2, char[1], char[2]>; // mp_list<void, char[1], char[2]> 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 = /*...*/; 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...>`. `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 L1 = std::pair<double, long double>;
using R1 = mp_rename<L1, std::tuple>; // std::tuple<double, long double> using R1 = mp_rename<L1, std::tuple>; // std::tuple<double, long double>
using L2 = std::tuple<void>; using L2 = std::tuple<void>;
using R2 = mp_rename<L2, mp_list>; // mp_list<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>; 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<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 L1 = std::pair<double, long double>;
using R1 = mp_apply<std::is_same, L1>; // std::is_same<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>; template<class Q, class L> using mp_apply_q = mp_apply<Q::template fn, L>;
Same as `mp_apply`, but takes a quoted metafunction. Same as `mp_apply`, but takes a quoted metafunction.
```
using L1 = std::tuple<double, long double>;
using L2 = mp_list<int, long>;
using L1 = std::tuple<double, long double>; using R1 = mp_apply_q<mp_bind_front<mp_push_back, L1>, L2>;
using L2 = mp_list<int, long>; // R1 is std::tuple<double, long double, int, long>
using R1 = mp_apply_q<mp_bind_front<mp_push_back, L1>, L2>; // std::tuple<double, long double, int, long> ```
[endsect] ## mp_append<L...>
[section `mp_append<L...>`]
template<class... L> using mp_append = /*...*/; 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<>` `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...>`. 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 L1 = std::tuple<double, long double>;
using L2 = mp_list<int>; using L2 = mp_list<int>;
using L3 = std::pair<short, long>; using L3 = std::pair<short, long>;
using L4 = mp_list<>; using L4 = mp_list<>;
using R1 = mp_append<L1, L2, L3, L4>; // std::tuple<double, long double, int, short, long> 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 = /*...*/; 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 `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
@@ -184,21 +192,21 @@ an alias for `L<T, U...>`.
using L1 = std::pair<int, float>; using L1 = std::pair<int, float>;
using R1 = mp_replace_front<L1, void>; // std::pair<void, float> using R1 = mp_replace_front<L1, void>; // std::pair<void, float>
using L2 = std::tuple<float, double, long double>; using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_front<L2, void>; // std::tuple<void, 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 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]>; 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>; 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_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 = /*...*/; 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>` `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>`
@@ -206,15 +214,15 @@ is an alias for `L<U1, T, U...>`.
using L1 = std::pair<int, float>; using L1 = std::pair<int, float>;
using R1 = mp_replace_second<L1, void>; // std::pair<int, void> using R1 = mp_replace_second<L1, void>; // std::pair<int, void>
using L2 = std::tuple<float, double, long double>; using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_second<L2, void>; // std::tuple<float, void, 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 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]>; 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 = /*...*/; 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>` `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>`
@@ -222,9 +230,6 @@ is an alias for `L<U1, U2, T, U...>`.
using L1 = std::tuple<float, double, long double>; using L1 = std::tuple<float, double, long double>;
using R1 = mp_replace_third<L1, void>; // std::tuple<float, double, void> 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 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]>; 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 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: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. 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 = /*...*/; 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_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>>; 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_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> >; 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`. 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 = /*...*/; 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, 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`. 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 = /*...*/; 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, 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...>>`. 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 = /*...*/; template<class M, class K> using mp_map_erase = /*...*/;
If the map `M` contains an element with a key `K`, removes it. 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 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: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. Mp11 is a C++11 metaprogramming library based on template aliases and variadic templates.
It implements the approach outlined in the article 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.html["Simple {cpp} metaprogramming"]
[@http://pdimov.com/cpp2/simple_cxx11_metaprogramming_2.html its sequel]. Reading these and http://pdimov.com/cpp2/simple_cxx11_metaprogramming_2.html[its sequel]. Reading these
articles before proceeding with this documentation is highly recommended. articles before proceeding with this documentation is _highly_ recommended.
The general principles upon which Mp11 is built are that algorithms and metafunctions are 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...>`, 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>>; using R = mp_transform<mp_list, std::tuple<int, float>>;
and get `std::tuple<mp_list<int>, mp_list<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 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: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. 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 = /*...*/; 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_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 = /*...*/; 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`. 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 = /*...*/; 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. `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 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: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 template<class T> struct mp_identity
{ {
using type = T; using type = T;
}; };
[endsect]
[section `mp_identity_t<T>`] ## mp_identity_t<T>
template<class T> using 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... {}; 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 = /*...*/; 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. `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 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 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...>; 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. 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 = /*...*/; 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 `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. 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...>; 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. 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...>; 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. 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 = /*...*/; 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_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 = /*...*/; 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, 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_defer<F, T...>` is an empty struct.
[endsect]
[section `mp_quote<F>`] ## mp_quote<F>
template<template<class...> class F> struct mp_quote template<template<class...> class F> struct mp_quote
{ {
template<class... T> using fn = F<T...>; 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_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...>; 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...>`. `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]