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