1
0
mirror of https://git.suyu.dev/suyu/suyu synced 2025-09-15 18:47:59 -05:00

Initial commit

This commit is contained in:
Crimson-Hawk
2024-03-05 16:42:40 +08:00
commit f1e4595ebf
39576 changed files with 7006612 additions and 0 deletions

View File

View File

View File

@@ -0,0 +1,96 @@
* text=auto !eol svneol=native#text/plain
*.gitattributes text svneol=native#text/plain
# Scriptish formats
*.bat text svneol=native#text/plain
*.bsh text svneol=native#text/x-beanshell
*.cgi text svneol=native#text/plain
*.cmd text svneol=native#text/plain
*.js text svneol=native#text/javascript
*.php text svneol=native#text/x-php
*.pl text svneol=native#text/x-perl
*.pm text svneol=native#text/x-perl
*.py text svneol=native#text/x-python
*.sh eol=lf svneol=LF#text/x-sh
configure eol=lf svneol=LF#text/x-sh
# Image formats
*.bmp binary svneol=unset#image/bmp
*.gif binary svneol=unset#image/gif
*.ico binary svneol=unset#image/ico
*.jpeg binary svneol=unset#image/jpeg
*.jpg binary svneol=unset#image/jpeg
*.png binary svneol=unset#image/png
*.tif binary svneol=unset#image/tiff
*.tiff binary svneol=unset#image/tiff
*.svg text svneol=native#image/svg%2Bxml
# Data formats
*.pdf binary svneol=unset#application/pdf
*.avi binary svneol=unset#video/avi
*.doc binary svneol=unset#application/msword
*.dsp text svneol=crlf#text/plain
*.dsw text svneol=crlf#text/plain
*.eps binary svneol=unset#application/postscript
*.gz binary svneol=unset#application/gzip
*.mov binary svneol=unset#video/quicktime
*.mp3 binary svneol=unset#audio/mpeg
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
*.ps binary svneol=unset#application/postscript
*.psd binary svneol=unset#application/photoshop
*.rdf binary svneol=unset#text/rdf
*.rss text svneol=unset#text/xml
*.rtf binary svneol=unset#text/rtf
*.sln text svneol=native#text/plain
*.swf binary svneol=unset#application/x-shockwave-flash
*.tgz binary svneol=unset#application/gzip
*.vcproj text svneol=native#text/xml
*.vcxproj text svneol=native#text/xml
*.vsprops text svneol=native#text/xml
*.wav binary svneol=unset#audio/wav
*.xls binary svneol=unset#application/vnd.ms-excel
*.zip binary svneol=unset#application/zip
# Text formats
.htaccess text svneol=native#text/plain
*.bbk text svneol=native#text/xml
*.cmake text svneol=native#text/plain
*.css text svneol=native#text/css
*.dtd text svneol=native#text/xml
*.htm text svneol=native#text/html
*.html text svneol=native#text/html
*.ini text svneol=native#text/plain
*.log text svneol=native#text/plain
*.mak text svneol=native#text/plain
*.qbk text svneol=native#text/plain
*.rst text svneol=native#text/plain
*.sql text svneol=native#text/x-sql
*.txt text svneol=native#text/plain
*.xhtml text svneol=native#text/xhtml%2Bxml
*.xml text svneol=native#text/xml
*.xsd text svneol=native#text/xml
*.xsl text svneol=native#text/xml
*.xslt text svneol=native#text/xml
*.xul text svneol=native#text/xul
*.yml text svneol=native#text/plain
boost-no-inspect text svneol=native#text/plain
CHANGES text svneol=native#text/plain
COPYING text svneol=native#text/plain
INSTALL text svneol=native#text/plain
Jamfile text svneol=native#text/plain
Jamroot text svneol=native#text/plain
Jamfile.v2 text svneol=native#text/plain
Jamrules text svneol=native#text/plain
Makefile* text svneol=native#text/plain
README text svneol=native#text/plain
TODO text svneol=native#text/plain
# Code formats
*.c text svneol=native#text/plain
*.cpp text svneol=native#text/plain
*.h text svneol=native#text/plain
*.hpp text svneol=native#text/plain
*.ipp text svneol=native#text/plain
*.tpp text svneol=native#text/plain
*.jam text svneol=native#text/plain
*.java text svneol=native#text/plain

View File

@@ -0,0 +1,502 @@
name: CI
on:
pull_request:
push:
branches:
- master
- develop
- feature/**
env:
UBSAN_OPTIONS: print_stacktrace=1
jobs:
posix:
strategy:
fail-fast: false
matrix:
include:
- toolset: gcc-4.8
cxxstd: "03,11"
os: ubuntu-18.04
install: g++-4.8
- toolset: gcc-5
cxxstd: "03,11,14,1z"
os: ubuntu-18.04
install: g++-5
- toolset: gcc-6
cxxstd: "03,11,14,1z"
os: ubuntu-18.04
install: g++-6
- toolset: gcc-7
cxxstd: "03,11,14,17"
os: ubuntu-18.04
- toolset: gcc-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
install: g++-8
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: gcc-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: g++-10
- toolset: gcc-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: g++-11
- toolset: clang
compiler: clang++-3.9
cxxstd: "03,11,14"
os: ubuntu-18.04
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "03,11,14"
os: ubuntu-18.04
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "03,11,14,1z"
os: ubuntu-18.04
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
cxxstd: "03,11,14,17"
os: ubuntu-18.04
install: clang-6.0
- toolset: clang
compiler: clang++-7
cxxstd: "03,11,14,17"
os: ubuntu-18.04
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "03,11,14,17"
os: ubuntu-20.04
install: clang-8
- toolset: clang
compiler: clang++-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: clang-9
- toolset: clang
compiler: clang++-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-12
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-10.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
./bootstrap.sh
./b2 -d0 headers
- name: Create user-config.jam
if: matrix.compiler
run: |
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
- name: Run tests
run: |
cd ../boost-root
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release
windows:
strategy:
fail-fast: false
matrix:
include:
# msvc-14.0 not included, because it fails with "compiler is out of heap space"
- toolset: msvc-14.1
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2016
- toolset: msvc-14.2
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.3
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2022
- toolset: gcc
cxxstd: "03,11,14,17,2a"
addrmd: 64
os: windows-2019
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
- name: Run tests
shell: cmd
run: |
cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release
posix-cmake-subdir:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: macos-10.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Use library with add_subdirectory
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test
mkdir __build__ && cd __build__
cmake ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-install:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: macos-10.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local ..
- name: Install
run: |
cd ../boost-root/__build__
cmake --build . --target install
- name: Use the installed library
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-test:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: macos-10.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON ..
- name: Build tests
run: |
cd ../boost-root/__build__
cmake --build . --target tests
- name: Run tests
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error
standalone-cmake-subdir:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: macos-10.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Use library with add_subdirectory
run: |
cd test/cmake_subdir_test
mkdir __build__ && cd __build__
cmake ..
cmake --build .
ctest --output-on-failure --no-tests=error
standalone-cmake-install:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: macos-10.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Configure
run: |
mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
- name: Install
run: |
cd __build__
cmake --build . --target install
- name: Use the installed library
run: |
cd test/cmake_install_test && mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
cmake --build .
ctest --output-on-failure --no-tests=error
standalone-cmake-test:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: macos-10.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Configure
run: |
mkdir __build__ && cd __build__
cmake -DBUILD_TESTING=ON ..
- name: Build tests
run: |
cd __build__
cmake --build . --target tests
- name: Run tests
run: |
cd __build__
ctest --output-on-failure --no-tests=error
cuda-linux:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: Jimver/cuda-toolkit@v0.2.4
- name: Setup Boost
run: |
cd ..
git clone --depth 1 https://github.com/boostorg/assert
git clone --depth 1 https://github.com/boostorg/config
git clone --depth 1 https://github.com/boostorg/core
- name: Run Tests
run: |
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++11 -c test/mp11.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++14 -c test/mp11.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++17 -c test/mp11.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++11 -c test/mp_all.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++14 -c test/mp_all.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++17 -c test/mp_all.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++11 -c test/mp_any.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++14 -c test/mp_any.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++17 -c test/mp_any.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++11 -c test/mp_count.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++14 -c test/mp_count.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++17 -c test/mp_count.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++11 -c test/mp_count_if.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++14 -c test/mp_count_if.cpp
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -std=c++17 -c test/mp_count_if.cpp
cuda-windows:
runs-on: windows-2019
steps:
- uses: actions/checkout@v2
- uses: Jimver/cuda-toolkit@v0.2.4
- uses: ilammy/msvc-dev-cmd@v1
- name: Setup Boost
run: |
cd ..
git clone --depth 1 https://github.com/boostorg/assert
git clone --depth 1 https://github.com/boostorg/config
git clone --depth 1 https://github.com/boostorg/core
- name: Run Tests
shell: cmd
run: |
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -c test/mp11.cpp || exit /b
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -c test/mp_all.cpp || exit /b
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -c test/mp_any.cpp || exit /b
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -c test/mp_count.cpp || exit /b
nvcc -x cu -I ./include -I ../assert/include -I ../config/include -I ../core/include -c test/mp_count_if.cpp || exit /b

View File

@@ -0,0 +1,419 @@
# Copyright 2016, 2017, 2018 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
language: cpp
os: linux
dist: xenial
branches:
only:
- master
- develop
- /feature\/.*/
env:
matrix:
- BOGUS_JOB=true
matrix:
exclude:
- env: BOGUS_JOB=true
include:
- os: linux
compiler: g++-4.7
env: TOOLSET=gcc COMPILER=g++-4.7 CXXSTD=11
addons:
apt:
packages:
- g++-4.7
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-4.8
env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD=11
addons:
apt:
packages:
- g++-4.8
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-4.9
env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD=11
addons:
apt:
packages:
- g++-4.9
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-5
env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=11,14,1z
addons:
apt:
packages:
- g++-5
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-6
env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=11,14,1z
addons:
apt:
packages:
- g++-6
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-7
env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=11,14,1z
addons:
apt:
packages:
- g++-7
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-8
env: TOOLSET=gcc COMPILER=g++-8 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- g++-8
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-9
env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- g++-9
sources:
- ubuntu-toolchain-r-test
- os: linux
dist: bionic
compiler: g++-10
env: TOOLSET=gcc COMPILER=g++-10 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- g++-10
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++
env: NVCC=1
before_script:
- wget https://developer.nvidia.com/compute/cuda/9.1/Prod/local_installers/cuda_9.1.85_387.26_linux
- sh cuda_9.1.85_387.26_linux --silent --toolkit --override --toolkitpath=$HOME/lib/cuda-9.1.85
script:
- $HOME/lib/cuda-9.1.85/bin/nvcc -x cu -I . -c -std=c++11 libs/mp11/test/mp11.cpp
- os: linux
dist: trusty
compiler: /usr/bin/clang++
env: TOOLSET=clang COMPILER=/usr/bin/clang++ CXXSTD=11
addons:
apt:
packages:
- clang-3.3
- os: linux
dist: trusty
compiler: /usr/bin/clang++
env: TOOLSET=clang COMPILER=/usr/bin/clang++ CXXSTD=11
addons:
apt:
packages:
- clang-3.4
- os: linux
compiler: clang++-3.5
env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=11,14,1z
addons:
apt:
packages:
- clang-3.5
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: clang++-3.6
env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD=11,14,1z
addons:
apt:
packages:
- clang-3.6
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: clang++-3.7
env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD=11,14,1z
addons:
apt:
packages:
- clang-3.7
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: clang++-3.8
env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=11,14,1z
addons:
apt:
packages:
- clang-3.8
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: clang++-3.9
env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=11,14,1z
addons:
apt:
packages:
- clang-3.9
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: clang++-4.0
env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=11,14,1z
addons:
apt:
packages:
- clang-4.0
sources:
- ubuntu-toolchain-r-test
- os: linux
dist: bionic
compiler: clang++-5.0
env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=11,14,1z
addons:
apt:
packages:
- clang-5.0
sources:
- ubuntu-toolchain-r-test
- os: linux
dist: bionic
compiler: clang++-6.0
env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=11,14,17
addons:
apt:
packages:
- clang-6.0
sources:
- ubuntu-toolchain-r-test
- os: linux
dist: bionic
compiler: clang++-7
env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-7
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-bionic-7
- os: linux
dist: bionic
compiler: clang++-8
env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-bionic-8
- os: linux
dist: bionic
compiler: clang++-9
env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-9
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
dist: bionic
compiler: clang++-10
env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-10
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
dist: bionic
compiler: clang++-11
env: TOOLSET=clang COMPILER=clang++-11 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-11
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
dist: bionic
compiler: clang++-12
env: TOOLSET=clang COMPILER=clang++-12 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-12
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-12 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
compiler: clang++-libc++
env: TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=11,14,1z
addons:
apt:
packages:
- libc++-dev
- os: linux
dist: bionic
compiler: clang++-5.0
env: CLANG_X_CUDA=1
addons:
apt:
packages:
- clang-5.0
- nvidia-profiler
- nvidia-cuda-dev
- nvidia-cuda-toolkit
sources:
- ubuntu-toolchain-r-test
script:
- clang++-5.0 -I . -c -x cuda -nocudainc -nocudalib --cuda-gpu-arch=sm_30 -D__device__="__attribute__((device))" -std=c++11 libs/mp11/test/mp11.cpp
- clang++-5.0 -I . -c -x cuda -nocudainc -nocudalib --cuda-gpu-arch=sm_30 -D__device__="__attribute__((device))" -std=c++14 libs/mp11/test/mp11.cpp
- clang++-5.0 -I . -c -x cuda -nocudainc -nocudalib --cuda-gpu-arch=sm_30 -D__device__="__attribute__((device))" -std=c++1z libs/mp11/test/mp11.cpp
- os: osx
osx_image: xcode7.3
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: osx
osx_image: xcode8.3
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: osx
osx_image: xcode9.4
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: osx
osx_image: xcode10.3
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: osx
osx_image: xcode11.6
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: osx
osx_image: xcode12.2
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: linux
compiler: clang++
env: CMAKE_STANDALONE_TEST=1
install: true
script:
- mkdir __build__ && cd __build__
- cmake ..
- cmake --build . --target tests
- ctest --output-on-failure
- os: linux
compiler: clang++
env: CMAKE_SUBDIR_TEST=1
install: true
script:
- cd test/cmake_subdir_test && mkdir __build__ && cd __build__
- cmake ..
- cmake --build .
- cmake --build . --target check
- os: linux
compiler: clang++
env: CMAKE_INSTALL_TEST=1
install: true
script:
- mkdir __build__ && cd __build__
- cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
- cmake --build . --target install
- cd ../test/cmake_install_test && mkdir __build__ && cd __build__
- cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
- cmake --build .
- cmake --build . --target check
- os: linux
compiler: clang++
env: BOOST_CMAKE_TEST=1
script:
- mkdir __build__ && cd __build__
- cmake -DBUILD_TESTING=ON -DBOOST_INCLUDE_LIBRARIES=mp11 ..
- cmake --build . --target tests
- ctest --output-on-failure
install:
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
- cd ..
- git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
- cd boost-root
- git submodule update --init tools/boostdep
- mkdir -p libs/mp11
- cp -r $TRAVIS_BUILD_DIR/* libs/mp11
- python tools/boostdep/depinst/depinst.py mp11
- ./bootstrap.sh
- ./b2 headers
script:
- |-
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
- ./b2 -j3 libs/mp11/test toolset=$TOOLSET cxxstd=$CXXSTD ${CXXFLAGS:+cxxflags="$CXXFLAGS"}
notifications:
email:
on_success: always

View File

@@ -0,0 +1,66 @@
# Copyright 2018, 2019 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
cmake_minimum_required(VERSION 3.5...3.16)
project(boost_mp11 VERSION 1.79.0 LANGUAGES CXX)
add_library(boost_mp11 INTERFACE)
add_library(Boost::mp11 ALIAS boost_mp11)
target_include_directories(boost_mp11 INTERFACE include)
target_compile_features(boost_mp11 INTERFACE cxx_alias_templates cxx_variadic_templates cxx_decltype)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
# Fetch support files
message(STATUS "Fetching BoostFetch.cmake")
file(DOWNLOAD
"https://raw.githubusercontent.com/boostorg/cmake/develop/include/BoostFetch.cmake"
"${CMAKE_BINARY_DIR}/fetch_and_include/BoostFetch.cmake"
)
include("${CMAKE_BINARY_DIR}/fetch_and_include/BoostFetch.cmake")
boost_fetch(boostorg/cmake TAG develop NO_ADD_SUBDIR)
FetchContent_GetProperties(boostorg_cmake)
list(APPEND CMAKE_MODULE_PATH ${boostorg_cmake_SOURCE_DIR}/include)
# Testing (off by default)
option(BUILD_TESTING "Build the tests." OFF)
include(CTest)
if(BUILD_TESTING)
set(BUILD_TESTING OFF) # hide cache variable
boost_fetch(boostorg/assert TAG develop EXCLUDE_FROM_ALL)
boost_fetch(boostorg/config TAG develop EXCLUDE_FROM_ALL)
boost_fetch(boostorg/core TAG develop EXCLUDE_FROM_ALL)
boost_fetch(boostorg/static_assert TAG develop EXCLUDE_FROM_ALL)
boost_fetch(boostorg/throw_exception TAG develop EXCLUDE_FROM_ALL)
unset(BUILD_TESTING)
endif()
# Do not use the default BoostInstall versioned layout on Windows when standalone
set(BOOST_INSTALL_LAYOUT "system" CACHE STRING "Installation layout (versioned, tagged, or system)")
include(BoostInstall)
boost_install(TARGETS boost_mp11 HEADER_DIRECTORY include/)
endif()
if(BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,23 @@
# Mp11, a C++11 metaprogramming library
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"](https://www.boost.org/libs/mp11/doc/html/simple_cxx11_metaprogramming.html)
and [its sequel](https://www.boost.org/libs/mp11/doc/html/simple_cxx11_metaprogramming_2.html).
Mp11 is part of [Boost](http://boost.org/libs/mp11), starting with release 1.66.0. It
however has no Boost dependencies and can be used standalone, as a Git submodule, for
instance. For CMake users, `add_subdirectory` is supported, as is installation and
`find_package(boost_mp11)`.
## Supported compilers
* g++ 4.8 or later
* clang++ 3.9 or later
* Visual Studio 2013, 2015, 2017, 2019
Tested on [Github Actions](https://github.com/boostorg/mp11/actions) and [Appveyor](https://ci.appveyor.com/project/pdimov/mp11/).
## License
Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).

View File

@@ -0,0 +1,86 @@
# Copyright 2016-2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
version: 1.0.{build}-{branch}
shallow_clone: true
branches:
only:
- master
- develop
- /feature\/.*/
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
TOOLSET: msvc-12.0
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc-14.0
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc-14.1
CXXSTD: 14,17,latest
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: clang-win
CXXSTD: 14,17,latest
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
CMAKE: 1
CONFIG: MinSizeRel
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
CMAKE_SUBDIR: 1
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
CMAKE_INSTALL: 1
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
CMAKE_SUBDIR: 1
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
CMAKE_INSTALL: 1
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
CMAKE_SUBDIR: 1
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
CMAKE_INSTALL: 1
install:
- set BOOST_BRANCH=develop
- if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master
- cd ..
- git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
- cd boost-root
- git submodule update --init tools/boostdep
- xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\mp11\
- python tools/boostdep/depinst/depinst.py mp11
- cmd /c bootstrap
- b2 -d0 headers
build: off
test_script:
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
- if "%CMAKE%%CMAKE_SUBDIR%%CMAKE_INSTALL%" == "" b2 -j3 libs/mp11/test toolset=%TOOLSET% %CXXSTD% address-model=32,64 variant=debug,release embed-manifest-via=linker
- if not "%CMAKE%" == "" mkdir __build__ && cd __build__
- if not "%CMAKE%" == "" cmake -DBUILD_TESTING=ON -DBOOST_INCLUDE_LIBRARIES=mp11 ..
- if not "%CMAKE%" == "" cmake --build . --target tests --config %CONFIG%
- if not "%CMAKE%" == "" ctest --output-on-failure --no-tests=error -C %CONFIG%
- if not "%CMAKE_SUBDIR%" == "" cd libs/mp11/test/cmake_subdir_test && mkdir __build__ && cd __build__
- if not "%CMAKE_SUBDIR%" == "" cmake ..
- if not "%CMAKE_SUBDIR%" == "" cmake --build . --config Debug && cmake --build . --target check --config Debug
- if not "%CMAKE_SUBDIR%" == "" cmake --build . --config Release && cmake --build . --target check --config Release
- if not "%CMAKE_INSTALL%" == "" cd libs/mp11 && mkdir __build__ && cd __build__
- if not "%CMAKE_INSTALL%" == "" cmake -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
- if not "%CMAKE_INSTALL%" == "" cmake --build . --target install --config Debug
- if not "%CMAKE_INSTALL%" == "" cmake --build . --target install --config Release
- if not "%CMAKE_INSTALL%" == "" cd ../test/cmake_install_test && mkdir __build__ && cd __build__
- if not "%CMAKE_INSTALL%" == "" cmake -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
- if not "%CMAKE_INSTALL%" == "" cmake --build . --config Debug && cmake --build . --target check --config Debug
- if not "%CMAKE_INSTALL%" == "" cmake --build . --config Release && cmake --build . --target check --config Release

View File

@@ -0,0 +1,2 @@
/html/
/pdf/

View File

@@ -0,0 +1,48 @@
# 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 asciidoctor ;
html mp11.html : mp11.adoc ;
html simple_cxx11_metaprogramming.html :
article/simple_cxx11_metaprogramming.adoc ;
html simple_cxx11_metaprogramming_2.html :
article/simple_cxx11_metaprogramming_2.adoc ;
install html_ :
mp11.html
simple_cxx11_metaprogramming.html
simple_cxx11_metaprogramming_2.html :
<location>html ;
pdf mp11.pdf : mp11.adoc ;
pdf simple_cxx11_metaprogramming.pdf :
article/simple_cxx11_metaprogramming.adoc ;
pdf simple_cxx11_metaprogramming_2.pdf :
article/simple_cxx11_metaprogramming_2.adoc ;
explicit mp11.pdf
simple_cxx11_metaprogramming.pdf
simple_cxx11_metaprogramming_2.pdf ;
install pdf_ :
mp11.pdf
simple_cxx11_metaprogramming.pdf
simple_cxx11_metaprogramming_2.pdf :
<location>pdf ;
explicit pdf_ ;
###############################################################################
alias boostdoc ;
explicit boostdoc ;
alias boostrelease : html_ ;
explicit boostrelease ;

View File

@@ -0,0 +1,6 @@
<style>
*:not(pre)>code { background: none; color: #600000; }
/* table tr.even, table tr.alt, table tr:nth-of-type(even) { background: none; } */
</style>

View File

@@ -0,0 +1,984 @@
////
Copyright 2015-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
////
# Simple {cpp}11 metaprogramming, part 2
Peter Dimov
2015-06-20
:toc: left
:idprefix:
:docinfo: shared-footer
[.lead]
__Efficient algorithms for membership testing, random access, and retrieval by
key__
NOTE: Being late to the metaprogramming party, I make no claim of having
invented the techniques in this article. A quick look at the implementations
of, for example, Louis Dionne's https://github.com/ldionne/mpl11[mpl11] and
Eric Niebler's https://github.com/ericniebler/meta[meta], shows that most of
these tricks are already known. Dave Abrahams
https://github.com/dabrahams/mpl11[has experimented] along these lines in 2012.
The original inventor of the multiple inheritance trick and the `void*`
arguments trick is probably Richard Smith, who has posted
https://llvm.org/bugs/attachment.cgi?id=8825[two]
https://llvm.org/bugs/attachment.cgi?id=8838[examples] in response to
https://llvm.org/bugs/show_bug.cgi?id=13263[a Clang bug report].
## Vectors, sets, and maps
<<simple_cxx11_metaprogramming.adoc#,Last time>>, I outlined a style of
metaprogramming that operated on type lists -- variadic class templates:
```
template<class... T> struct mp_list {};
```
Classic Lisp uses lists as its only data structure, but operating on a list is
usually linear in the number of its elements.
In addition to `list`, the STL has `vector`, `set`, and `map`. `vector`
supports random access by index; `set` has efficient test for membership; `map`
associates keys with values and has efficient lookup based on key.
Instead of introducing separate data structure such as `mp_vector`, `mp_set`,
`mp_map`, we'll keep our data in a list form, and attempt to provide efficient
algorithms for random access, membership testing, and lookup.
## mp_contains
Let's starts with sets. A set is just a list with unique elements. To obtain a
set from an arbitrary list, we'll need an algorithm that removes the
duplicates. Let's call it `mp_unique<L>`:
[subs=+quotes]
```
// mp_if
template<bool C, class T, class E> struct mp_if_c_impl;
template<class T, class E> struct mp_if_c_impl<true, T, E>
{
using type = T;
};
template<class T, class E> struct mp_if_c_impl<false, T, E>
{
using type = E;
};
template<bool C, class T, class E>
using mp_if_c = typename mp_if_c_impl<C, T, E>::type;
template<class C, class T, class E>
using mp_if = typename mp_if_c_impl<C::value != 0, T, E>::type;
// mp_unique
template<class L> struct mp_unique_impl;
template<class L> using mp_unique = typename mp_unique_impl<L>::type;
template<template<class...> class L> struct mp_unique_impl<L<>>
{
using type = L<>;
};
template<template<class...> class L, class T1, class... T>
struct mp_unique_impl<L<T1, T...>>
{
using _rest = mp_unique<L<T...>>;
using type = mp_if<**mp_contains**<_rest, T1>, _rest, mp_push_front<_rest, T1>>;
};
```
For membership testing, we've introduced an algorithm `mp_contains<L, V>` that
returns `true` when `L` contains `V`. The straightforward recursive
implementation of `mp_contains` is:
```
template<class L, class V> struct mp_contains_impl;
template<class L, class V> using mp_contains = typename mp_contains_impl<L, V>::type;
template<template<class...> class L, class V> struct mp_contains_impl<L<>, V>
{
using type = std::false_type;
};
template<template<class...> class L, class... T, class V>
struct mp_contains_impl<L<V, T...>, V>
{
using type = std::true_type;
};
template<template<class...> class L, class T1, class... T, class V>
struct mp_contains_impl<L<T1, T...>, V>: mp_contains_impl<L<T...>, V>
{
};
```
Note that `mp_unique<L>` makes `N` calls to `mp_contains`, where `N` is the
length of the list `L`. This means that `mp_contains` needs to be as fast as
possible, which the above implementation, well, isn't.
Here are the compile times in seconds for invoking `mp_unique` on a list with
`N` (distinct) elements:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, recursive |2.1 |DNF ||||||
|clang$$++$$ 3.5.1, recursive |0.9 |4.5 |13.2 |30.2 |DNF |||
|g$$++$$ 4.9.2, recursive |0.7 |3.6 |10.4 |23.2 |DNF |||
|===
(Tests done under Windows/Cygwin. All compilers are 32 bit. No optimizations.
DNF stands for "did not finish", which usually means that the compiler ran out
of heap space or crashed.)
We clearly need a better alternative.
I ended the previous article with an implementation of `mp_contains` that
relied on `mp_count`, which in turn relied on `mp_plus`. Let's see how it
fares:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, mp_count/mp_plus |1.1 |9.8 |50.5 |DNF ||||
|clang$$++$$ 3.5.1, mp_count/mp_plus |0.5 |1.4 |3.1 |6.1 |DNF |||
|g$$++$$ 4.9.2, mp_count/mp_plus |0.5 |1.3 |2.9 |5.8 |9.7 |15.6 |22.4 |32.3
|===
Not _that_ bad, at least if your compiler happens to be `g$$++$$`. Still, there
ought to be room for improvement here.
To do better, we have to somehow leverage the language features, such as pack
expansion, to do more of the work for us. For inspiration, let's turn to
section 14.5.3 paragraph 4 of the {cpp}11 standard, which explains that pack
expansions can occur in the following contexts:
* **In a function parameter pack (8.3.5); the pattern is the
__parameter-declaration__ without the ellipsis.**
* In a template parameter pack that is a pack expansion (14.1):
* **In an __initializer-list__ (8.5); the pattern is an
__initializer-clause__.**
* **In a __base-specifier-list__ (Clause 10); the pattern is a
__base-specifier__.**
* In a __mem-initializer-list__ (12.6.2); the pattern is a
__mem-initializer__.
* In a __template-argument-list__ (14.3); the pattern is a
__template-argument__.
* In a __dynamic-exception-specification__ (15.4); the pattern is a
__type-id__.
* In an __attribute-list__ (7.6.1); the pattern is an __attribute__.
* In an __alignment-specifier__ (7.6.2); the pattern is the
__alignment-specifier__ without the ellipsis.
* In a __capture-list__ (5.1.2); the pattern is a __capture__.
* In a `sizeof$$...$$` expression (5.3.3); the pattern is an __identifier__.
The **emphasis** is mine and indicates possible leads.
Our first option is to expand the parameter pack into arguments for a function
call. Since we're interested in operations that occur at compile time, calling
a function may not appear useful; but {cpp}11 functions can be `constexpr`, and
`constexpr` function "calls" do occur at compile time.
Recall our `mp_count`:
```
template<class L, class V> struct mp_count_impl;
template<template<class...> class L, class... T, class V>
struct mp_count_impl<L<T...>, V>
{
using type = mp_plus<std::is_same<T, V>...>;
};
template<class L, class V> using mp_count = typename mp_count_impl<L, V>::type;
```
Instead of using the template alias `mp_plus` to sum the `is_same` expressions,
we can use a `constexpr` function:
```
constexpr std::size_t cx_plus()
{
return 0;
}
template<class T1, class... T> constexpr std::size_t cx_plus(T1 t1, T... t)
{
return t1 + cx_plus(t...);
}
// mp_size_t
template<std::size_t N> using mp_size_t = std::integral_constant<std::size_t, N>;
// mp_count
template<class L, class V> struct mp_count_impl;
template<template<class...> class L, class... T, class V>
struct mp_count_impl<L<T...>, V>
{
using type = mp_size_t<cx_plus(std::is_same<T, V>::value...)>;
};
template<class L, class V> using mp_count = typename mp_count_impl<L, V>::type;
```
with the following results:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|clang$$++$$ 3.5.1, mp_count/cx_plus |0.4 |1.1 |2.5 |5.0 |DNF |||
|g$$++$$ 4.9.2, mp_count/cx_plus |0.4 |0.9 |1.7 |2.9 |4.7 |6.7 |9.2 |11.8
|===
We've improved the times, but lost VC$$++$$ 2013 due to its not implementing
`constexpr`.
Let's try pack expansion into an __initializer-list__. Instead of passing the
`is_same` expressions to a function, we can build a constant array out of them,
then sum the array with a `constexpr` function:
```
constexpr std::size_t cx_plus2(bool const * first, bool const * last)
{
return first == last? 0: *first + cx_plus2(first + 1, last);
}
// mp_count
template<class L, class V> struct mp_count_impl;
template<template<class...> class L, class... T, class V>
struct mp_count_impl<L<T...>, V>
{
static constexpr bool _v[] = { std::is_same<T, V>::value... };
using type = mp_size_t<cx_plus2(_v, _v + sizeof...(T))>;
};
template<class L, class V> using mp_count = typename mp_count_impl<L, V>::type;
```
This is a neat trick, but is it fast?
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|clang$$++$$ 3.5.1, mp_count/cx_plus2 |0.4 |0.9 |1.8 |DNF ||||
|g$$++$$ 4.9.2, mp_count/cx_plus2 |0.4 |0.9 |1.9 |3.4 |5.4 |7.8 |11.0 |14.7
|===
That's a bit disappointing. Let's see what can we do with expanding a parameter
pack into a base-specifier-list. We would be able to define a class that
derives from every element of the pack:
```
struct U: T... {};
```
We can then use `std::is_base_of<V, U>` to test whether a type `V` is a base of
`U`, that is, whether it's one of the elements of the parameter pack. Which is
exactly what we need.
Arbitrary types such as `void`, `int`, or `void(int)` can't be used as base
classes, but we'll wrap the types in an empty class template, which we'll call
`mp_identity`.
```
template<class T> struct mp_identity
{
using type = T;
};
template<class L, class V> struct mp_contains_impl;
template<class L, class V> using mp_contains = typename mp_contains_impl<L, V>::type;
template<template<class...> class L, class... T, class V>
struct mp_contains_impl<L<T...>, V>
{
struct U: mp_identity<T>... {};
using type = std::is_base_of<mp_identity<V>, U>;
};
```
Performance?
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, is_base_of |0.3 |0.6 |1.3 |2.5 |DNF |||
|clang$$++$$ 3.5.1, is_base_of |0.3 |0.4 |0.6 |0.8 |DNF |||
|g$$++$$ 4.9.2, is_base_of |0.3 |0.4 |0.6 |0.9 |1.3 |1.7 |2.3 |3.0
|===
This implementation is a clear winner.
In fairness, we ought to note that the first four implementations of
`mp_contains` do not rely on the list elements being unique. This makes
`mp_contains` an algorithm that supports arbitrary lists, not just sets.
The `is_base_of` implementation, however, does not support lists that contain
duplicates, because it's not possible to inherit directly from the same type
twice. So it does not implement the general `mp_contains`, but something that
should probably be named `mp_set_contains`.
We can avoid the "no duplicates" requirement by modifying the implementation to
inherit from `mp_identity<T>` indirectly, via an intermediate base class:
[subs=+macros]
```
// indirect_inherit
template<std::size_t I, class T> struct inherit_second: T {};
template<class L, class S> struct indirect_inherit_impl;
template<template<class...> class L, class... T, std::size_t... J>
struct indirect_inherit_impl<L<T...>, http://en.cppreference.com/w/cpp/utility/integer_sequence[integer_sequence]<std::size_t, J...>>:
inherit_second<J, mp_identity<T>>... {};
template<class L> using indirect_inherit =
indirect_inherit_impl<L, http://en.cppreference.com/w/cpp/utility/integer_sequence[make_index_sequence]<mp_size<L>::value>>;
// mp_contains
template<class L, class V> struct mp_contains_impl
{
using U = indirect_inherit<L>;
using type = std::is_base_of<mp_identity<V>, U>;
};
template<class L, class V> using mp_contains = typename mp_contains_impl<L, V>::type;
```
This, however, pretty much nullifies the spectacular performance gains we've
observed with the original `is_base_of`-based implementation:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, recursive |2.1 |DNF ||||||
|VC$$++$$ 2013, mp_count/mp_plus |1.1 |9.8 |50.5 |DNF ||||
|VC$$++$$ 2013, is_base_of |0.3 |0.6 |1.3 |2.5 |DNF |||
|VC$$++$$ 2013, is_base_of/indirect |1.0 |9.3 |49.5 |153.8 |DNF |||
|===
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|clang$$++$$ 3.5.1, recursive |0.9 |4.5 |13.2 |30.2 |DNF |||
|clang$$++$$ 3.5.1, mp_count/mp_plus |0.5 |1.4 |3.1 |6.1 |DNF |||
|clang$$++$$ 3.5.1, mp_count/cx_plus |0.4 |1.1 |2.5 |5.0 |DNF |||
|clang$$++$$ 3.5.1, mp_count/cx_plus2 |0.4 |0.9 |1.8 |DNF ||||
|clang$$++$$ 3.5.1, is_base_of |0.3 |0.4 |0.6 |0.8 |DNF |||
|clang$$++$$ 3.5.1, is_base_of/indirect |0.4 |0.9 |1.6 |2.5 |DNF |||
|===
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|g$$++$$ 4.9.2, recursive |0.7 |3.6 |10.4 |23.2 |DNF |||
|g$$++$$ 4.9.2, mp_count/mp_plus |0.5 |1.3 |2.9 |5.8 |9.7 |15.6 |22.4 |32.3
|g$$++$$ 4.9.2, mp_count/cx_plus |0.4 |0.9 |1.7 |2.9 |4.7 |6.7 |9.2 |11.8
|g$$++$$ 4.9.2, mp_count/cx_plus2 |0.4 |0.9 |1.9 |3.4 |5.4 |7.8 |11.0 |14.7
|g$$++$$ 4.9.2, is_base_of |0.3 |0.4 |0.6 |0.9 |1.3 |1.7 |2.3 |3.0
|g$$++$$ 4.9.2, is_base_of/indirect |0.5 |1.1 |2.3 |4.0 |6.6 |9.8 |13.6 |18.2
|===
## mp_map_find
A map, in the STL sense, is a data structure that associates keys with values
and can efficiently retrieve, given a key, its associated value. For our
purposes, a map will be any list of lists for which the inner lists have at
least one element, the key; the rest of the elements we'll consider to be the
associated value. For example, the list
```
[[A, B], [C, D, E], [F], [G, H]]
```
is a map with keys `A`, `C`, `F`, and `G`, with associated values `[B]`,
`[D, E]`, `[]`, and `[H]`, respectively. We'll require unique keys, for reasons
that'll become evident later.
I'll show two other examples of maps, this time using real {cpp} code:
```
using Map = mp_list<mp_list<int, int*>, mp_list<void, void*>, mp_list<char, char*>>;
```
```
using Map2 = std::tuple<std::pair<int, int[2]>, std::pair<char, char[2]>>;
```
The Lisp name of the algorithm that performs retrieval based on key is `ASSOC`,
but I'll call it `mp_map_find`. `mp_map_find<M, K>` returns the element of `M`
whose first element is `K`. For example, `mp_map_find<Map2, int>` would return
`std::pair<int, int[2]>`. If there's no such key, it returns `void`.
There's almost no need to implement and benchmark the recursive version of
`mp_map_find` -- we can be pretty sure it will perform horribly. Still,
```
template<class M, class K> struct mp_map_find_impl;
template<class M, class K> using mp_map_find = typename mp_map_find_impl<M, K>::type;
template<template<class...> class M, class K> struct mp_map_find_impl<M<>, K>
{
using type = void;
};
template<template<class...> class M, class T1, class... T, class K>
struct mp_map_find_impl<M<T1, T...>, K>
{
using type = mp_if<std::is_same<mp_front<T1>, K>, T1, mp_map_find<M<T...>, K>>;
};
```
The compile time, in seconds, for `N` lookups into a map of size `N`, is as
follows:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, recursive |38.2 |DNF ||||||
|clang$$++$$ 3.5.1, recursive |2.5 |13.7 |DNF |||||
|g$$++$$ 4.9.2, recursive |1.9 |10.2 |28.8 |DNF ||||
|===
I told you there was no point.
But, I hear some of you say, you're evaluating the else branch even if the
condition is true, and that's horribly inefficient!
Well, this would only improve the performance by a factor of approximately two
on average, and only if the element is present, but fine, let's try it. The
element happens to be present in the benchmark, so let's see.
```
// mp_eval_if
template<bool C, class T, template<class...> class E, class... A>
struct mp_eval_if_c_impl;
template<class T, template<class...> class E, class... A>
struct mp_eval_if_c_impl<true, T, E, A...>
{
using type = T;
};
template<class T, template<class...> class E, class... A>
struct mp_eval_if_c_impl<false, T, E, A...>
{
using type = E<A...>;
};
template<bool C, class T, template<class...> class E, class... A>
using mp_eval_if_c = typename mp_eval_if_c_impl<C, T, E, A...>::type;
template<class C, class T, template<class...> class E, class... A>
using mp_eval_if = typename mp_eval_if_c_impl<C::value != 0, T, E, A...>::type;
// mp_map_find
template<class M, class K> struct mp_map_find_impl;
template<class M, class K> using mp_map_find = typename mp_map_find_impl<M, K>::type;
template<template<class...> class M, class K> struct mp_map_find_impl<M<>, K>
{
using type = void;
};
template<template<class...> class M, class T1, class... T, class K>
struct mp_map_find_impl<M<T1, T...>, K>
{
using type = mp_eval_if<std::is_same<mp_front<T1>, K>, T1, mp_map_find, M<T...>, K>;
};
```
There you go:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, recursive |15.6 |DNF ||||||
|clang$$++$$ 3.5.1, recursive |1.8 |9.5 |DNF |||||
|g$$++$$ 4.9.2, recursive |1.4 |7.0 |19.7 |DNF ||||
|===
I told you there was no point.
Point or no, to establish that the recursive implementation is inefficient is
not the same as to come up with an efficient one. There are two things that
make the `mp_contains` techniques inapplicable to our present case: first,
`mp_contains` only had to return true or false, whereas `mp_map_find` returns a
type, and second, in `mp_contains` we knew the exact type of the element for
which we were looking, whereas here, we only know its `mp_front`.
Fortunately, there does exist a language feature that can solve both: {cpp} can
deduce the template parameters of base classes when passed a derived class. In
this example,
```
struct K1 {};
struct V1 {};
struct X: std::pair<K1, V1> {};
template<class A, class B> void f(std::pair<A, B> const & p);
int main()
{
f(X());
}
```
the call to `f(X())` deduces `A` as `K1` and `B` as `V1`. If we have more than
one `std::pair` base class, we can fix `A` to be `K1`:
```
struct K1 {};
struct V1 {};
struct K2 {};
struct V2 {};
struct X: std::pair<K1, V1>, std::pair<K2, V2> {};
template<class B> void f(std::pair<K1, B> const & p);
int main()
{
f(X());
}
```
and `B` will be deduced as `V1`.
We can retrieve the results of the deduction by returning the type we want:
```
template<class B> std::pair<K1, B> f(std::pair<K1, B> const & p);
```
and then using `decltype(f(X()))` to obtain this return type.
What if `X` doesn't have a base of type `std::pair<K1, B>`? The deduction will
fail and we'll get an error that `f(X())` cannot be called. To avoid it, we can
add an overload of `f` that takes anything and returns `void`. But in this
case, what will happen if `X` has two bases of the form that match the first
`f` overload, such as for example `std::pair<K1, Y>` and `std::pair<K1, Z>`?
The deduction will fail, the second overload will again be chosen and we'll get
`void`. This is why we require maps to have unique keys.
Here's an implementation of `mp_map_find` based on this technique:
```
template<class M, class K> struct mp_map_find_impl;
template<class M, class K>
using mp_map_find = typename mp_map_find_impl<M, K>::type;
template<template<class...> class M, class... T, class K>
struct mp_map_find_impl<M<T...>, K>
{
struct U: mp_identity<T>... {};
template<template<class...> class L, class... U>
static mp_identity<L<K, U...>>
f( mp_identity<L<K, U...>>* );
static mp_identity<void> f( ... );
using V = decltype( f((U*)0) );
using type = typename V::type;
};
```
and its corresponding compile times:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, deduction |0.3 |0.7 |1.8 |3.6 |6.4 |10.4 |16.2 |DNF
|clang$$++$$ 3.5.1, deduction |0.3 |0.4 |0.6 |0.9 |1.2 |1.6 |2.2 |2.7
|g$$++$$ 4.9.2, deduction |0.3 |0.5 |0.9 |1.6 |2.3 |3.4 |4.7 |6.3
|===
This looks ready to ship.
The implementation contains one inefficiency though. If we evaluate
`mp_map_find<M, K1>`, then `mp_map_find<M, K2>`, the two nested `U` types are
the same as they only depend on `M`, but the compiler doesn't know that and
will instantiate each one separately. We should move this type outside
`mp_map_find_impl` so that it can be reused:
[subs=+quotes]
```
template<class... T> struct **mp_inherit**: T... {};
template<class M, class K> struct mp_map_find_impl;
template<class M, class K>
using mp_map_find = typename mp_map_find_impl<M, K>::type;
template<template<class...> class M, class... T, class K>
struct mp_map_find_impl<M<T...>, K>
{
**using U = mp_inherit<mp_identity<T>...>;**
template<template<class...> class L, class... U>
static mp_identity<L<K, U...>>
f( mp_identity<L<K, U...>>* );
static mp_identity<void> f( ... );
using V = decltype( f((U*)0) );
using type = typename V::type;
};
```
(This same optimization, by the way, applies to our `is_base_of` implementation
of `mp_contains`.)
The improvement in compile times on our benchmark is measurable:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, deduction+mp_inherit |0.3 |0.6 |1.4 |2.6 |4.5 |7.1 |10.7 |DNF
|clang$$++$$ 3.5.1, deduction+mp_inherit |0.3 |0.4 |0.6 |0.8 |1.0 |1.4 |1.8 |2.2
|g$$++$$ 4.9.2, deduction+mp_inherit |0.3 |0.4 |0.6 |0.9 |1.3 |1.8 |2.3 |2.9
|===
## mp_at
With sets and maps covered, it's time to tackle vectors. Vectors for us are
just lists, to which we'll need to add the ability to efficiently access an
element based on its index. The customary name for this accessor is
`mp_at<L, I>`, where `L` is a list and `I` is an `integral_constant` that
represents the index. We'll also follow the Boost.MPL convention and add
`mp_at_c<L, I>`, where `I` is the index of type `size_t`.
The recursive implementation of `mp_at` is:
```
template<class L, std::size_t I> struct mp_at_c_impl;
template<class L, std::size_t I> using mp_at_c = typename mp_at_c_impl<L, I>::type;
template<class L, class I> using mp_at = typename mp_at_c_impl<L, I::value>::type;
template<template<class...> class L, class T1, class... T>
struct mp_at_c_impl<L<T1, T...>, 0>
{
using type = T1;
};
template<template<class...> class L, class T1, class... T, std::size_t I>
struct mp_at_c_impl<L<T1, T...>, I>
{
using type = mp_at_c<L<T...>, I-1>;
};
```
and the compile times for making `N` calls to `mp_at` with a list of size `N`
as the first argument are:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, recursive |3.6 |DNF ||||||
|clang$$++$$ 3.5.1, recursive |1.0 |5.1 |15.3 |DNF ||||
|g$$++$$ 4.9.2, recursive |0.9 |4.7 |14.2 |32.4 |DNF |||
|===
To improve upon this appalling result, we'll again exploit pack expansion into a
function call, but in a novel way. Let's suppose that we need to access the
fourth element (`I = 3`). We'll generate the function signature
```
template<class W> W f( void*, void*, void*, W*, ... );
```
and then, given a list `L<T1, T2, T3, T4, T5, T6, T7>`, we'll evaluate the
expression
```
decltype( f( (T1*)0, (T2*)0, (T3*)0, (T4*)0, (T5*)0, (T6*)0, (T7*)0 ) )
```
The three `void*` parameters will eat the first three elements, `W` will be
deduced as the fourth, and the ellipsis will take care of the rest.
A working implementation based on this technique is shown below:
```
// mp_repeat_c
template<std::size_t N, class... T> struct mp_repeat_c_impl
{
using _l1 = typename mp_repeat_c_impl<N/2, T...>::type;
using _l2 = typename mp_repeat_c_impl<N%2, T...>::type;
using type = mp_append<_l1, _l1, _l2>;
};
template<class... T> struct mp_repeat_c_impl<0, T...>
{
using type = mp_list<>;
};
template<class... T> struct mp_repeat_c_impl<1, T...>
{
using type = mp_list<T...>;
};
template<std::size_t N, class... T> using mp_repeat_c =
typename mp_repeat_c_impl<N, T...>::type;
// mp_at
template<class L, class L2> struct mp_at_c_impl;
template<template<class...> class L, class... T,
template<class...> class L2, class... U>
struct mp_at_c_impl<L<T...>, L2<U...>>
{
template<class W> static W f( U*..., W*, ... );
using R = decltype( f( (mp_identity<T>*)0 ... ) );
using type = typename R::type;
};
template<class L, std::size_t I> using mp_at_c =
typename mp_at_c_impl<L, mp_repeat_c<I, void>>::type;
template<class L, class I> using mp_at = mp_at_c<L, I::value>;
```
and the compile times in the following table show it to be good enough for most
practical purposes.
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, void* |0.4 |1.1 |2.4 |4.7 |DNF |||
|clang$$++$$ 3.5.1, void* |0.4 |0.7 |1.2 |1.9 |2.7 |3.8 |5.0 |6.6
|g$$++$$ 4.9.2, void* |0.3 |0.5 |0.9 |1.3 |2.1 |3.0 |4.2 |5.5
|===
Are we done with `mp_at`, then?
Let's try something else -- transform the input list `[T1, T2, T3]` into a map
`[[0, T1], [1, T2], [2, T3]]`, then use `mp_map_find` for the lookup:
[subs=+macros]
```
// mp_map_from_list
template<class L, class S> struct mp_map_from_list_impl;
template<template<class...> class L, class... T, std::size_t... J>
struct mp_map_from_list_impl<L<T...>, http://en.cppreference.com/w/cpp/utility/integer_sequence[integer_sequence]<std::size_t, J...>>
{
using type = mp_list<mp_list<mp_size_t<J>, T>...>;
};
template<class L> using mp_map_from_list = typename mp_map_from_list_impl<L,
http://en.cppreference.com/w/cpp/utility/integer_sequence[make_index_sequence]<mp_size<L>::value>>::type;
// mp_at
template<class L, std::size_t I> struct mp_at_c_impl
{
using map = mp_map_from_list<L>;
using type = mp_second<mp_map_find<map, mp_size_t<I>>>;
};
template<class L, std::size_t I> using mp_at_c = typename mp_at_c_impl<L, I>::type;
template<class L, class I> using mp_at = typename mp_at_c_impl<L, I::value>::type;
```
At first sight, this looks ridiculous, but metaprogramming has its own rules.
Let's measure:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, map |0.3 |0.7 |1.5 |2.9 |5.0 |7.8 |11.9 |DNF
|clang$$++$$ 3.5.1, map |0.3 |0.4 |0.6 |0.8 |1.1 |1.5 |1.8 |2.3
|g$$++$$ 4.9.2, map |0.3 |0.4 |0.7 |1.0 |1.4 |1.9 |2.5 |3.2
|===
Surprise, this is the best implementation.
## mp_drop
It turned out that we didn't need the `void*` trick for `mp_at`, but I'll show
an example where we do: `mp_drop`. `mp_drop<L, N>` returns the list `L` without
its first `N` elements; or, in other words, it drops the first `N` elements
(presumably on the cutting room floor) and returns what's left.
To implement `mp_drop`, we just need to change
```
template<class W> W f( void*, void*, void*, W*, ... );
```
from above to return the rest of the elements, rather than just one:
```
template<class... W> mp_list<W> f( void*, void*, void*, W*... );
```
Adding the necessary `mp_identity` seasoning produces the following working
implementation:
```
template<class L, class L2> struct mp_drop_c_impl;
template<template<class...> class L, class... T,
template<class...> class L2, class... U>
struct mp_drop_c_impl<L<T...>, L2<U...>>
{
template<class... W> static mp_identity<L<W...>> f( U*..., mp_identity<W>*... );
using R = decltype( f( (mp_identity<T>*)0 ... ) );
using type = typename R::type;
};
template<class L, std::size_t N> using mp_drop_c =
typename mp_drop_c_impl<L, mp_repeat_c<N, void>>::type;
template<class L, class N> using mp_drop = mp_drop_c<L, N::value>;
```
I'll skip the recursive implementation and the performance comparison for this
one. We can pretty much tell who's going to win, and by how much.
## mp_find_index
The final algorithm that I'll bring to your attention is `mp_find_index`.
`mp_find_index<L, V>` returns an integral constant of type `size_t` with a
value that is the index of the first occurrence of `V` in `L`. If `V` is not in
`L`, the return value is the size of `L`.
We'll start with the recursive implementation, as usual:
```
template<class L, class V> struct mp_find_index_impl;
template<class L, class V> using mp_find_index = typename mp_find_index_impl<L, V>::type;
template<template<class...> class L, class V> struct mp_find_index_impl<L<>, V>
{
using type = mp_size_t<0>;
};
template<template<class...> class L, class... T, class V>
struct mp_find_index_impl<L<V, T...>, V>
{
using type = mp_size_t<0>;
};
template<template<class...> class L, class T1, class... T, class V>
struct mp_find_index_impl<L<T1, T...>, V>
{
using type = mp_size_t<1 + mp_find_index<L<T...>, V>::value>;
};
```
and will continue with the compile times for `N` calls to `mp_find_index` on a
list with `N` elements, as usual:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, recursive |3.5 |DNF ||||||
|clang$$++$$ 3.5.1, recursive |1.1 |5.5 |DNF |||||
|g$$++$$ 4.9.2, recursive |0.8 |4.6 |13.6 |DNF ||||
|===
What can we do here?
Let's go back to `mp_contains` and look at the "mp_count/cx_plus2"
implementation which we rejected in favor of the inheritance-based one. It
built a `constexpr` array of booleans and summed them in a `constexpr`
function. We can do the same here, except instead of summing the array, we can
find the index of the first true value:
```
template<class L, class V> struct mp_find_index_impl;
template<class L, class V> using mp_find_index = typename mp_find_index_impl<L, V>::type;
template<template<class...> class L, class V> struct mp_find_index_impl<L<>, V>
{
using type = mp_size_t<0>;
};
constexpr std::size_t cx_find_index( bool const * first, bool const * last )
{
return first == last || *first? 0: 1 + cx_find_index( first + 1, last );
}
template<template<class...> class L, class... T, class V>
struct mp_find_index_impl<L<T...>, V>
{
static constexpr bool _v[] = { std::is_same<T, V>::value... };
using type = mp_size_t< cx_find_index( _v, _v + sizeof...(T) ) >;
};
```
The performance of this version is:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|clang$$++$$ 3.5.1, constexpr |0.5 |1.3 |2.9 |DNF ||||
|g$$++$$ 4.9.2, constexpr |0.5 |1.4 |3.1 |5.5 |8.7 |13.0 |18.0 |DNF
|===
which, while not ideal, is significantly better than our recursive punching
bag. But if our compiler of choice is VC$$++$$ 2013, we can't use `constexpr`.
We may attempt an implementation along the same lines, but with the `constexpr`
function replaced with ordinary metaprogramming:
```
template<class L, class V> struct mp_find_index_impl;
template<class L, class V> using mp_find_index = typename mp_find_index_impl<L, V>::type;
template<template<class...> class L, class V> struct mp_find_index_impl<L<>, V>
{
using type = mp_size_t<0>;
};
template<bool...> struct find_index_impl_;
template<> struct find_index_impl_<>
{
static const std::size_t value = 0;
};
template<bool B1, bool... R> struct find_index_impl_<B1, R...>
{
static const std::size_t value = B1? 0: 1 + find_index_impl_<R...>::value;
};
template<bool B1, bool B2, bool B3, bool B4, bool B5,
bool B6, bool B7, bool B8, bool B9, bool B10, bool... R>
struct find_index_impl_<B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, R...>
{
static const std::size_t value = B1? 0: B2? 1: B3? 2: B4? 3: B5? 4:
B6? 5: B7? 6: B8? 7: B9? 8: B10? 9: 10 + find_index_impl_<R...>::value;
};
template<template<class...> class L, class... T, class V>
struct mp_find_index_impl<L<T...>, V>
{
using type = mp_size_t<find_index_impl_<std::is_same<T, V>::value...>::value>;
};
```
This is still recursive, so we don't expect miracles, but it wouldn't hurt to
measure:
|===
||N=100 |N=200 |N=300 |N=400 |N=500 |N=600 |N=700 |N=800
|VC$$++$$ 2013, bool... |4.7 |94.5 |488.3 |XFA ||||
|clang$$++$$ 3.5.1, bool... |0.6 |2.2 |5.8 |12.0 |21.7 |35.2 |DNF |
|g$$++$$ 4.9.2, bool... |0.6 |2.4 |6.5 |13.2 |23.8 |39.1 |59.0 |DNF
|===
(where XFA stands for "experimenter fell asleep".)
This is an interesting tradeoff for VC$$++$$ 2013 and Clang. On the one hand,
this implementation is slower; on the other, it doesn't crash the compiler as
easily. Which to prefer is a matter of taste and of stern evaluation of one's
needs to manipulate type lists of length 300.
Note that once we have `mp_drop` and `mp_find_index`, we can derive the
`mp_find<L, V>` algorithm, which returns the suffix of `L` starting with the
first occurrence of `V`, if any, and an empty list otherwise, by using
`mp_drop<L, mp_find_index<L, V>>`.
## Conclusion
In this article, I have shown efficient algorithms that allow us to treat type
lists as sets, maps and vectors, demonstrating various {cpp}11 implementation
techniques in the process.

View File

@@ -0,0 +1,7 @@
<style>
*:not(pre)>code { background: none; color: #600000; }
:not(pre):not([class^=L])>code { background: none; color: #600000; }
table tr.even, table tr.alt, table tr:nth-of-type(even) { background: none; }
</style>

View File

@@ -0,0 +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
////
# Boost.Mp11: A C++11 metaprogramming library
Peter Dimov
:toc: left
:toclevels: 3
:idprefix:
:listing-caption: Code Example
:table-caption: Illustration
:docinfo: private-footer
:source-highlighter: rouge
:source-language: c++
:leveloffset: +1
include::mp11/overview.adoc[]
include::mp11/definitions.adoc[]
include::mp11/examples.adoc[]
include::mp11/changelog.adoc[]
include::mp11/reference.adoc[]
:leveloffset: -1
[appendix]
## Copyright, License, and Acknowledgments
This documentation is
* Copyright 2017-2019 Peter Dimov
* Copyright 2017 Bjørn Reese
and is distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].
The "Simple {cpp}11 metaprogramming" articles have been graciously converted to Asciidoc format for incorporation
into this documentation by Glen Fernandes.

View File

@@ -0,0 +1,976 @@
////
Copyright 2017-2019 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
////
[#algorithm]
# Algorithms, <boost/mp11/algorithm.hpp>
:toc:
:toc-title:
:idprefix:
## 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>...>`.
.Using mp_transform to produce a list of pointers from a list of pointees
```
template<class T> using add_pointer_t =
typename std::add_pointer<T>::type; // std::add_pointer_t in C++14
using L1 = std::tuple<void, int, float>;
using R1 = mp_transform<add_pointer_t, L1>; // std::tuple<void*, int*, float*>
```
.Using mp_transform to compare the contents of two lists of types
```
using L1 = std::tuple<void, int, float>;
using L2 = mp_list<void, int, float>;
using R1 = mp_apply<mp_all, mp_transform<std::is_same, L1, L2>>; // mp_true
```
.Using mp_transform to compare the contents of two lists of integral constants
```
template<class T1, class T2> using eq = mp_bool<T1::value == T2::value>;
using L1 = std::tuple<mp_int<1>, mp_int<2>, mp_int<3>>;
using L2 = mp_list<mp_size_t<1>, mp_size_t<2>, mp_size_t<3>>;
using R1 = mp_apply<mp_all, mp_transform<eq, L1, L2>>; // mp_true
```
.mp_transform on one list
[cols="<.^4m,4*^.^1m",width=85%]
|===
|*L1*|A~1~|A~2~|...|A~n~
5+|
|*mp_transform<F, L1>*|F<A~1~>|F<A~2~>|...|F<A~n~>
|===
.mp_transform on two lists
[cols="<.^4m,4*^.^1m",width=85%]
|===
|*L1*|A~1~|A~2~|...|A~n~
5+|
|*L2*|B~1~|B~2~|...|B~n~
5+|
|*mp_transform<F, L1, L2>*|F<A~1~,B~1~>|F<A~2~,B~2~>|...|F<A~n~,B~n~>
|===
## 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.
.Using mp_transform_q to count the occurrences of `void` in a list
```
using L1 = std::tuple<void, int, float, void, int>;
using R1 = mp_apply<mp_plus,
mp_transform_q<mp_bind_front<std::is_same, void>, L1>>; // mp_int\<2>
```
[cols="<.^4m,4*^.^1m",width=85%]
.mp_transform_q on two lists
|===
|*L1*|A~1~|A~2~|...|A~n~
5+|
|*L2*|B~1~|B~2~|...|B~n~
5+|
|*mp_transform_q<Q, L1, L2>*|Q::fn<A~1~,B~1~>|Q::fn<A~2~,B~2~>|...|Q::fn<A~n~,B~n~>
|===
## 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`.
.Using mp_transform_if to replace the occurrences of 'void' in a list with the corresponding elements of a second list
```
using L1 = std::tuple<void, int, float, void, int>;
using L2 = std::tuple<char[1], char[2], char[3], char[4], char[5]>;
template<class T1, class T2> using first_is_void = std::is_same<T1, void>;
template<class T1, class T2> using second = T2;
using R1 = mp_transform_if<first_is_void, second, L1, L2>;
// std::tuple<char[1], int, float, char[4], int>
```
.mp_transform_if
[cols="<.^4m,4*^.^1m",width=85%]
|===
|*L1*|A~1~|A~2~|...|A~n~
5+|
|*L2*|B~1~|B~2~|...|B~n~
5+|
|*P<A~i~, B~i~>*|mp_false|mp_true|...|mp_false
5+|
|*mp_transform_if<P, F, L1, L2>*|A~1~|F<A~2~,B~2~>|...|A~n~
|===
## 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 quoted metafunctions.
.Using mp_transform_if_q to replace the occurrences of 'void' in a list with the corresponding elements of a second list
```
using L1 = std::tuple<void, int, float, void, int>;
using L2 = std::tuple<char[1], char[2], char[3], char[4], char[5]>;
using R1 = mp_transform_if_q<mp_bind<std::is_same, _1, void>, _2, L1, L2>;
// std::tuple<char[1], int, float, char[4], int>
```
.mp_transform_if_q
[cols="<.^4m,4*^.^1m",width=85%]
|===
|*L1*|A~1~|A~2~|...|A~n~
5+|
|*L2*|B~1~|B~2~|...|B~n~
5+|
|*Qp::fn<A~i~, B~i~>*|mp_false|mp_true|...|mp_false
5+|
|*mp_transform_if_q<Qp, _2, L1, L2>*|A~1~|B~2~|...|A~n~
|===
## mp_filter<P, L...>
template<template<class...> class P, class... L> using mp_filter = /*...*/;
`mp_filter<P, L1, L2, ..., Ln>` removes the elements of the list `L1` for which `mp_to_bool<P<T1, T2, ..., Tn>>`
is `mp_false` and returns the result, where `Ti` are the corresponding elements of `Li`.
See also `mp_copy_if` and `mp_remove_if`, less general variants of `mp_filter` that only take a single list.
## mp_filter_q<Qp, L...>
template<class Qp, class... L> using mp_filter_q =
mp_filter<Qp::template fn, L...>;
As `mp_filter`, but takes a quoted metafunction.
.Using mp_filter_q to pick elements of a list based on a mask in another list
```
using L1 = std::tuple<void, int, float>;
using L2 = mp_list<mp_true, mp_false, mp_true>;
using R1 = mp_filter_q<_2, L1, L2>; // std::tuple<void, float>
```
## 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.
.Using mp_fill with std::tuple
```
using L1 = std::tuple<void, int, float>;
using R1 = mp_fill<L1, double>; // std::tuple<double, double, double>
```
.Using mp_fill with std::pair
```
using L1 = std::pair<int, float>;
using R1 = mp_fill<L1, void>; // std::pair<void, void>
```
.mp_fill
[cols="<.^4m,4*^.^1m",width=85%]
|===
|*L1*|A~1~|A~2~|...|A~n~
5+|
|*mp_fill<L1, V>*|V|V|...|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`.
## mp_count_if<L, P>
template<class L, template<class...> class P> using mp_count_if = /*...*/;
`mp_count_if<L, P>` returns `mp_size_t<N>`, where `N` is the number of elements `T` of `L` for which `mp_to_bool<P<T>>` is `mp_true`.
## mp_count_if_q<L, Q>
template<class L, class Q> using mp_count_if_q = mp_count_if<L, Q::template fn>;
As `mp_count_if`, but takes a quoted metafunction.
## mp_contains<L, V>
template<class L, class V> using mp_contains = mp_to_bool<mp_count<L, V>>;
`mp_contains<L, V>` is `mp_true` when `L` contains an element `V`, `mp_false` otherwise.
## mp_starts_with<L1, L2>
template<class L1, class L2> using mp_starts_with = /*...*/;
`mp_starts_with<L1, L2>` is `mp_true` when `L1` starts with `L2`, `mp_false`
otherwise.
## mp_repeat_c<L, N>
template<class L, std::size_t N> using mp_repeat_c = /*...*/;
`mp_repeat_c<L, N>` returns a list of the same form as `L` that consists of `N` concatenated copies of `L`.
.Using mp_repeat_c
```
using L1 = tuple<int>;
using R1 = mp_repeat_c<L1, 3>; // tuple<int, int, int>
using L2 = pair<int, float>;
using R2 = mp_repeat_c<L2, 1>; // pair<int, float>
using L3 = mp_list<int, float>;
using R3 = mp_repeat_c<L3, 2>; // mp_list<int, float, int, float>
using L4 = mp_list<int, float, double>;
using R4 = mp_repeat_c<L4, 0>; // mp_list<>
```
## mp_repeat<L, N>
template<class L, class N> using mp_repeat = /*...*/;
Same as `mp_repeat_c` but with a type argument `N`. The number of copies is `N::value` and must be nonnegative.
## mp_product<F, L...>
template<template<class...> class F, class... L> using mp_product = /*...*/;
`mp_product<F, L1<T1...>, L2<T2...>, ..., Ln<Tn...>>` evaluates `F<U1, U2, ..., Un>` for values `Ui` taken from
the Cartesian product of the lists, as if the elements `Ui` are formed by `n` nested loops, each traversing `Li`.
It returns a list of the form `L1<V...>` containing the results of the application of `F`. The degenerate case
of zero lists, `mp_product<F>`, returns `mp_list<F<>>`.
.mp_product on two lists
[cols="<.^4m,4*^.^1m",width=85%]
|===
|*L1*|A~1~|A~2~|...|A~n~
5+|
|*L2*|B~1~|B~2~|...|B~m~
5+|
|*mp_product<F, L1, L2>*|F<A~1~,B~1~>|F<A~1~,B~2~>|...|F<A~1~,B~m~>
||F<A~2~,B~1~>|F<A~2~,B~2~>|...|F<A~2~,B~m~>
|
4+|...
||F<A~n~,B~1~>|F<A~n~,B~2~>|...|F<A~n~,B~m~>
|===
## mp_product_q<Q, L...>
template<class Q, class... L> using mp_product_q = mp_product<Q::template fn, L...>;
As `mp_product`, but takes a quoted metafunction.
## mp_power_set<L>
template<class L> using mp_power_set = /*...*/;
`mp_power_set<L>` returns a list (of the same form as `L`) of all possible 2^n^ subsets of `L` (where `n` is the length of `L`.)
`mp_power_set<L<>>` returns `L<L<>>`.
`mp_power_set<L<T1>>` returns `L<L<>, L<T1>>`.
`mp_power_set<L<T1, T2>>` returns `L<L<>, L<T2>, L<T1>, L<T1, T2>>`.
`mp_power_set<L<T1, T...>>` returns the concatenation of `mp_power_set<L<T...>>` and that same list with `T1` prepended to each element.
## mp_drop_c<L, N>
template<class L, std::size_t N> using mp_drop_c = /*...*/;
`mp_drop_c<L, N>` removes the first `N` elements of `L` and returns the result.
.mp_drop_c
[cols="<.^4m,6*^.^1m",width=85%]
|===
|*L1*|A~1~|...|A~m~|A~m+1~|...|A~n~
7+|
|*mp_drop_c<L1, M>*|A~m+1~|...|A~n~ 3+|
|===
## mp_drop<L, N>
template<class L, class N> using mp_drop = /*...*/;
Same as `mp_drop_c`, but with a type argument `N`. `N::value` must be a nonnegative number.
## mp_from_sequence<S>
template<class S> using mp_from_sequence = /*...*/
`mp_from_sequence` transforms an integer sequence produced by `make_integer_sequence` into an `mp_list`
of the corresponding `std::integral_constant` types. Given
template<class T, T... I> struct S;
`mp_from_sequence<S<T, I...>>` is an alias for `mp_list<std::integral_constant<T, I>...>`.
## mp_iota_c<N>
template<std::size_t N> using mp_iota_c = /*...*/;
`mp_iota_c<N>` is an alias for `mp_list<mp_size_t<0>, mp_size_t<1>, ..., mp_size_t<N-1>>`.
## mp_iota<N>
template<class N> using mp_iota = /*...*/;
Same as `mp_iota_c`, but with a type argument `N`. `N::value` must be a nonnegative number. Returns
`mp_list<std::integral_constant<T, 0>, std::integral_constant<T, 1>, ..., std::integral_constant<T, N::value-1>>`
where `T` is the type of `N::value`.
.mp_iota
[cols="<.^4m,4*^.^1m",width=85%]
|===
|*mp_iota<mp_int<4>>*|mp_int<0>|mp_int<1>|mp_int<2>|mp_int<3>
|===
## mp_at_c<L, I>
template<class L, std::size_t I> using mp_at_c = /*...*/;
`mp_at_c<L, I>` returns the `I`-th element of `L`, zero-based.
## mp_at<L, I>
template<class L, class I> using mp_at = /*...*/;
Same as `mp_at_c`, but with a type argument `I`. `I::value` must be a nonnegative number.
## mp_take_c<L, N>
template<class L, std::size_t N> using mp_take_c = /*...*/;
`mp_take_c<L, N>` returns a list of the same form as `L` containing the first `N` elements of `L`.
.mp_take_c
[cols="<.^4m,6*^.^1m",width=85%]
|===
|*L1*|A~1~|...|A~m~|A~m+1~|...|A~n~
7+|
|*mp_take_c<L1, M>*|A~1~|...|A~m~ 3+|
|===
## mp_take<L, N>
template<class L, class N> using mp_take = /*...*/;
Same as `mp_take_c`, but with a type argument `N`. `N::value` must be a nonnegative number.
## mp_back<L>
template<class L> using mp_back = mp_at_c<L, mp_size<L>::value - 1>;
`mp_back<L>` returns the last element of the list `L`.
## mp_pop_back<L>
template<class L> using mp_pop_back = mp_take_c<L, mp_size<L>::value - 1>;
`mp_pop_back<L>` removes the last element of the list `L` and returns the result.
## mp_insert_c<L, I, T...>
template<class L, std::size_t I, class... T> using mp_insert_c =
mp_append<mp_take_c<L, I>, mp_push_front<mp_drop_c<L, I>, T...>>;
Inserts the elements `T...` into the list `L` at position `I` (a zero-based index).
.mp_insert_c with two elements
[cols="<.^4m,8*^.^1m",width=85%]
|===
|*L1*|A~1~|...|A~m~|A~m+1~|...|A~n~ 2+|
9+|
|*mp_insert_c<L1, M, B~1~, B~2~>*|A~1~|...|A~m~|B~1~|B~2~|A~m+1~|...|A~n~
|===
## mp_insert<L, I, T...>
template<class L, class I, class... T> using mp_insert =
mp_append<mp_take<L, I>, mp_push_front<mp_drop<L, I>, T...>>;
Same as `mp_insert_c`, but with a type argument `I`.
## mp_erase_c<L, I, J>
template<class L, std::size_t I, std::size_t J> using mp_erase_c =
mp_append<mp_take_c<L, I>, mp_drop_c<L, J>>;
Removes from the list `L` the elements with indices from `I` (inclusive) to `J` (exclusive).
.mp_erase_c
[cols="<.^4m,9*^.^1m",width=85%]
|===
|*L1*|A~0~|...|A~i-1~|A~i~|...|A~j-1~|A~j~|...|A~n-1~
10+|
|*mp_erase_c<L1, I, J>*|A~0~|...|A~i-1~|A~j~|...|A~n-1~ 3+|
|===
## mp_erase<L, I, J>
template<class L, class I, class J> using mp_erase =
mp_append<mp_take<L, I>, mp_drop<L, J>>;
Same as `mp_erase_c`, but with a type arguments `I` and `J`.
## mp_replace<L, V, W>
template<class L, class V, class W> using mp_replace = /*...*/;
Replaces all `V` elements of `L` with `W` and returns the result.
.mp_replace
[cols="<.^4m,4*^.^1m",width=85%]
|===
|*L1*|A~1~|V|...|A~n~
5+|
|*mp_replace<L1, V, W>*|A~1~|W|...|A~n~
|===
## mp_replace_if<L, P, W>
template<class L, template<class...> class P, class W> using mp_replace_if = /*...*/;
Replaces all `T` elements of `L` for which `mp_to_bool<P<T>>` is `mp_true` with `W` and returns the result.
.mp_replace_if
[cols="<.^4m,4*^.^1m",width=85%]
|===
|*L1*|A~1~|A~2~|...|A~n~
5+|
|*P<A~i~>*|mp_false|mp_true|...|mp_false
5+|
|*mp_replace_if<L1, P, W>*|A~1~|W|...|A~n~
|===
## mp_replace_if_q<L, Q, W>
template<class L, class Q, class W> using mp_replace_if_q =
mp_replace_if<L, Q::template fn, W>;
As `mp_replace_if`, but takes a quoted metafunction.
## mp_replace_at_c<L, I, W>
template<class L, std::size_t I, class W> using mp_replace_at_c = /*...*/;
Replaces the element of `L` at zero-based index `I` with `W` and returns the result.
## mp_replace_at<L, I, W>
template<class L, class I, class W> using mp_replace_at = /*...*/;
Same as `mp_replace_at_c`, but with a type argument `I`. `I::value` must be a nonnegative number.
## mp_rotate_left_c<L, N>
template<class L, std::size_t N> using mp_rotate_left_c = /*...*/;
Moves the `N % M` initial elements of the list `L` to the back, where `M` is the size of `L`. Empty
lists are unchanged.
## mp_rotate_left<L, N>
template<class L, class N> using mp_rotate_left = /*...*/;
Same as `mp_rotate_left_c`, but with a type argument `N`. `N::value` must be a nonnegative number.
## mp_rotate_right_c<L, N>
template<class L, std::size_t N> using mp_rotate_right_c = /*...*/;
Moves the `N % M` trailing elements of the list `L` to the front, where `M` is the size of `L`. Empty
lists are unchanged.
## mp_rotate_right<L, N>
template<class L, class N> using mp_rotate_right = /*...*/;
Same as `mp_rotate_right_c`, but with a type argument `N`. `N::value` must be a nonnegative number.
## mp_copy_if<L, P>
template<class L, template<class...> class P> using mp_copy_if = /*...*/;
Copies the elements `T` of `L` for which `mp_to_bool<P<T>>` is `mp_true` to a new list of the same form and returns it.
## mp_copy_if_q<L, Q>
template<class L, class Q> using mp_copy_if_q = mp_copy_if<L, Q::template fn>;
As `mp_copy_if`, but takes a quoted metafunction.
## mp_remove<L, V>
template<class L, class V> using mp_remove = /*...*/;
Removes all `V` elements of `L` and returns the result.
## mp_remove_if<L, P>
template<class L, template<class...> class P> using mp_remove_if = /*...*/;
Removes all elements `T` of `L` for which `mp_to_bool<P<T>>` is `mp_true` and returns the result.
## mp_remove_if_q<L, Q>
template<class L, class Q> using mp_remove_if_q = mp_remove_if<L, Q::template fn>;
As `mp_remove_if`, but takes a quoted metafunction.
## mp_flatten<L>
template<class L, class L2 = mp_clear<L>> using mp_flatten = /*...*/;
Replaces all elements `T` of `L` that are lists of the same form as `L2` (that is, those for which
`mp_similar<T, L2>` is `mp_true`) with their elements and returns the result.
.Using mp_flatten
```
using L1 = tuple<int, tuple<>, void, tuple<float, double>>;
using R1 = mp_flatten<L1>; // tuple<int, void, float, double>
using L2 = mp_list<int, mp_list<float>, tuple<void>>;
using R2a = mp_flatten<L2>; // mp_list<int, float, tuple<void>>
using R2b = mp_flatten<L2, tuple<>>; // mp_list<int, mp_list<float>, void>
using L3 = mp_list<mp_list<float>, mp_list<mp_list<void>>>;
using R3 = mp_flatten<L3>; // mp_list<float, mp_list<void>>
```
## mp_intersperse<L, S>
template<class L, class S> using mp_intersperse = /*...*/;
Inserts the separator `S` between the elements of the list `L`.
`mp_intersperse<L<>, S>` is `L<>`. `mp_intersperse<L<T1>, S>` is `L<T1>`.
`mp_intersperse<L<T1, T2, T3, ..., Tn-1, Tn>, S>` is `L<T1, S, T2, S, T3, S, ..., Tn-1, S, Tn>`.
## mp_split<L, S>
template<class L, class S> using mp_split = /*...*/;
Splits the list `L` into segments at each separator `S` and returns a list of
the segments.
`mp_split<L<>, S>` is `L<L<>>`. `mp_split<L<T...>, S>`, where `S` does not occur in `T...`,
is `L<L<T...>>`. `mp_split<L<T1..., S, T2..., S, T3...>, S>` is `L<L<T1...>, L<T2...>, L<T3...>>`.
The segments may be empty; `mp_split<L<S, X, Y, S, S>, S>` is `L<L<>, L<X, Y>, L<>, L<>>`.
## mp_join<L, S>
template<class L, class S> using mp_join = /*...*/;
`mp_join` is the reverse operation of `mp_split`; it takes a list of segments `L` and joins
them into a single list, inserting the separator `S` between them.
`mp_join<mp_split<L, S>, S>` yields back the original list `L`.
For example, `mp_split<L<X1, X2, S, X3>, S>` gives `L<L<X1, X2>, L<X3>>`, and
`mp_join<L<L<X1, X2>, L<X3>>, S>` results in `L<X1, X2, S, X3>`.
`mp_join<L, S>` is equivalent to (and is implemented as) `mp_apply<mp_append, mp_intersperse<L, mp_list<S>>>`.
## mp_partition<L, P>
template<class L, template<class...> class P> using mp_partition = /*...*/;
`mp_partition<L<T...>, P>` partitions `L` into two lists `L<U1...>` and `L<U2...>` such that `mp_to_bool<P<T>>` is `mp_true`
for the elements of `L<U1...>` and `mp_false` for the elements of `L<U2...>`. Returns `L<L<U1...>, L<U2...>>`.
## mp_partition_q<L, Q>
template<class L, class Q> using mp_partition_q = mp_partition<L, Q::template fn>;
As `mp_partition`, but takes a quoted metafunction.
## 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>>`.
.Using mp_sort to sort a list of std::ratio values
----
#include <ratio>
using L1 = mp_list<std::ratio<1,2>, std::ratio<1,4>>;
using R1 = mp_sort<L1, std::ratio_less>; // mp_list<ratio<1,4>, ratio<1,2>>
----
## mp_sort_q<L, Q>
template<class L, class Q> using mp_sort_q = mp_sort<L, Q::template fn>;
As `mp_sort`, but takes a quoted metafunction.
## mp_nth_element_c<L, I, P>
template<class L, std::size_t I, template<class...> class P> using mp_nth_element_c =
/*...*/;
Returns the element at position `I` in `mp_sort<L, P>`.
## mp_nth_element<L, I, P>
template<class L, class I, template<class...> class P> using mp_nth_element = /*...*/;
Like `mp_nth_element_c`, but with a type argument `I`. `I::value` must be a nonnegative number.
## mp_nth_element_q<L, I, Q>
template<class L, class I, class Q> using mp_nth_element_q =
mp_nth_element<L, I, Q::template fn>;
Like `mp_nth_element`, but takes a quoted metafunction.
## mp_min_element<L, P>
template<class L, template<class...> class P> using mp_min_element = /*...*/;
`mp_min_element<L, P>` returns the minimal element of the list `L` according to the ordering `mp_to_bool<P<T, U>>`.
It's equivalent to `mp_fold<mp_rest<L>, mp_first<L>, F>`, where `F<T, U>` returns `mp_if<P<T, U>, T, U>`.
## mp_min_element_q<L, Q>
template<class L, class Q> using mp_min_element_q = mp_min_element<L, Q::template fn>;
As `mp_min_element`, but takes a quoted metafunction.
## mp_max_element<L, P>
template<class L, template<class...> class P> using mp_max_element = /*...*/;
`mp_max_element<L, P>` returns the maximal element of the list `L` according to the ordering `mp_to_bool<P<T, U>>`.
It's equivalent to `mp_fold<mp_rest<L>, mp_first<L>, F>`, where `F<T, U>` returns `mp_if<P<U, T>, T, U>`.
## mp_max_element_q<L, Q>
template<class L, class Q> using mp_max_element_q = mp_max_element<L, Q::template fn>;
As `mp_max_element`, but takes a quoted metafunction.
## 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 occurrence of `V` in `L`. If `L` does not contain `V`, `mp_find<L, V>`
is `mp_size<L>`.
## mp_find_if<L, P>
template<class L, template<class...> class P> using mp_find_if = /*...*/;
`mp_find_f<L, P>` is an alias for `mp_size_t<I>`, where `I` is the zero-based index of the first element `T` in `L` for which
`mp_to_bool<P<T>>` is `mp_true`. If there is no such element, `mp_find_if<L, P>` is `mp_size<L>`.
## mp_find_if_q<L, Q>
template<class L, class Q> using mp_find_if_q = mp_find_if<L, Q::template fn>;
As `mp_find_if`, but takes a quoted metafunction.
## mp_reverse<L>
template<class L> using mp_reverse = /*...*/;
`mp_reverse<L<T1, T2, ..., Tn>>` is `L<Tn, ..., T2, T1>`.
.mp_reverse
[cols="<.^4m,4*^.^1m",width=85%]
|===
|*L1*|A~1~|A~2~|...|A~n~
5+|
|*mp_reverse<L1>*|A~n~|A~n-1~|...|A~1~
|===
## 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.
.Using mp_fold to add the contents of a list of std::ratio values
----
#include <ratio>
using L1 = mp_list<std::ratio<1,8>, std::ratio<1,4>, std::ratio<1,2>>;
using R1 = mp_fold<L1, std::ratio<0,1>, std::ratio_add>; // std::ratio<7,8>
----
## mp_fold_q<L, V, Q>
template<class L, class V, class Q> using mp_fold_q =
mp_fold<L, V, Q::template fn>;
As `mp_fold`, but takes a quoted metafunction.
## mp_reverse_fold<L, V, F>
template<class L, class V, template<class...> class F> using mp_reverse_fold =
/*...*/;
`mp_reverse_fold<L<T1, T2, ..., Tn>, V, F>` is `F<T1, F<T2, F<..., F<Tn, V>>>>`, or `V`, if `L` is empty.
## mp_reverse_fold_q<L, V, Q>
template<class L, class V, class Q> using mp_reverse_fold_q =
mp_reverse_fold<L, V, Q::template fn>;
As `mp_reverse_fold`, but takes a quoted metafunction.
## mp_partial_sum<L, V, F>
template<class L, class V, template<class...> class F> using mp_partial_sum = /*...*/;
`mp_partial_sum<L, V, F>` is similar to `mp_fold<L, V, F>`, but instead of its final result, it returns
a list (of the same form as `L`) holding the intermediate results of the fold. The last element of the
result of `mp_partial_sum` is the same as the result of `mp_fold`.
For example, `mp_fold<mp_list<X1, X2, X3>, V, F>` is `F<F<F<V, X1>, X2>, X3>`, but
`mp_partial_sum<mp_list<X1, X2, X3>, V, F>` is `mp_list<F<V, X1>, F<F<V, X1>, X2>, F<F<F<V, X1>, X2>, X3>>`.
It's common for `F` to be `mp_plus`, in which case the result contains the partial sums of `L`.
.Using mp_partial_sum
----
using L1 = mp_list_c<int, 1, 2, 3, 4>;
using R1 = mp_partial_sum<L1, mp_int<0>, mp_plus>; // mp_list_c<int, 1, 3, 6, 10>
----
## mp_partial_sum_q<L, V, Q>
template<class L, class V, class Q> using mp_partial_sum_q =
mp_partial_sum<L, V, Q::template fn>;
As `mp_partial_sum`, but takes a quoted metafunction.
## mp_pairwise_fold<L, F>
template<class L, template<class...> class F> using mp_pairwise_fold = /*...*/;
`mp_pairwise_fold<L, F>` returns a list of the same form as `L` whose elements are
the result of the application of the binary metafunction `F` to each pair of adjacent
elements of `L`. That is, `mp_pairwise_fold<L<T1, T2, T3>, F>` is
`L<F<T1, T2>, F<T2, T3>>`.
The result has one fewer element than the original. If `L` has only one element, the
result is an empty list. If `L` is an empty list, the result is also an empty list.
.Using mp_pairwise_fold
----
template<class L> using is_increasing = mp_all_of<
mp_pairwise_fold<L, mp_less>, mp_to_bool>;
----
## mp_pairwise_fold_q<L, Q>
template<class L, class Q> using mp_pairwise_fold_q =
mp_pairwise_fold<L, Q::template fn>;
As `mp_pairwise_fold`, but takes a quoted metafunction.
.Using mp_pairwise_fold_q
----
template<class L, template<class...> class P> using is_sorted =
mp_none_of<mp_pairwise_fold_q<L, mp_bind<P, _2, _1>>, mp_to_bool>;
----
## mp_iterate<V, F, R>
template<class V, template<class...> class F, template<class...> class R>
using mp_iterate = /*...*/;
`mp_iterate<V, F, R>` applies `R` to `V` successively until that's no longer possible,
yielding the sequence `V`, `R<V>`, `R<R<V>>`, `R<R<R<V>>>`...
It then returns an `mp_list` whose elements are formed by applying `F` to the above
sequence of values. That is, it returns `mp_list<F<V>, F<R<V>>, F<R<R<V>>>, ...>`.
`mp_iterate` is in a way the reverse operation of `mp_reverse_fold`. Given
template<class T, class U> struct cons {};
struct nil {};
`mp_reverse_fold<mp_list<X1, X2, X3>, nil, cons>` produces `cons<X1, cons<X2, cons<X3, nil>>>`,
which when passed as `V` to `mp_iterate<V, mp_first, mp_second>` recovers the original
`mp_list<X1, X2, X3>`.
.Using mp_iterate
----
struct X1 {};
struct X2 {};
struct X3 {};
using L1 = mp_list<X1, X2, X3>;
using R1 = mp_iterate<L1, mp_first, mp_rest>; // L1
template<class T, class U> struct cons {};
struct nil {};
using V2 = mp_reverse_fold<L1, nil, cons>; // cons<X1, cons<X2, cons<X3, nil>>>
using R2 = mp_iterate<V2, mp_first, mp_second>; // L1
struct Y1 {};
struct Y2 { using value_type = double; using next_type = Y1; };
struct Y3 { using value_type = float; using next_type = Y2; };
struct Y4 { using value_type = int; using next_type = Y3; };
template<class T> using value_type = typename T::value_type;
template<class T> using next_type = typename T::next_type;
using R3 = mp_iterate<Y4, mp_identity_t, next_type>; // mp_list<Y4, Y3, Y2, Y1>
using R4 = mp_iterate<Y4, value_type, next_type>; // mp_list<int, float, double>
----
## mp_iterate_q<V, Qf, Qr>
template<class V, class Qf, class Qr> using mp_iterate_q =
mp_iterate<V, Qf::template fn, Qr::template fn>;
As `mp_iterate`, but takes quoted metafunctions.
## mp_unique<L>
template<class L> using mp_unique = /*...*/;
`mp_unique<L>` returns a list of the same form as `L` with the duplicate elements removed.
## mp_unique_if<L, P>
template<class L, template<class...> class P> using mp_unique_if = /*...*/;
As `mp_unique`, but two elements `T` and `U` are considered duplicates when `mp_to_bool<P<T, U>>` is `mp_true`.
## mp_unique_if_q<L, Q>
template<class L, class Q> using mp_unique_if_q =
mp_unique_if<L, Q::template fn>;
As `mp_unique_if`, but takes a quoted metafunction.
## mp_all_of<L, P>
template<class L, template<class...> class P> using mp_all_of =
mp_bool< mp_count_if<L, P>::value == mp_size<L>::value >;
`mp_all_of<L, P>` is `mp_true` when `P` holds for all elements of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_true`.
## mp_all_of_q<L, Q>
template<class L, class Q> using mp_all_of_q = mp_all_of<L, Q::template fn>;
As `mp_all_of`, but takes a quoted metafunction.
## mp_none_of<L, P>
template<class L, template<class...> class P> using mp_none_of =
mp_bool< mp_count_if<L, P>::value == 0 >;
`mp_none_of<L, P>` is `mp_true` when `P` holds for no element of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_true`.
## mp_none_of_q<L, Q>
template<class L, class Q> using mp_none_of_q = mp_none_of<L, Q::template fn>;
As `mp_none_of`, but takes a quoted metafunction.
## mp_any_of<L, P>
template<class L, template<class...> class P> using mp_any_of =
mp_bool< mp_count_if<L, P>::value != 0 >;
`mp_any_of<L, P>` is `mp_true` when `P` holds for at least one element of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_false`.
## mp_any_of_q<L, Q>
template<class L, class Q> using mp_any_of_q = mp_any_of<L, Q::template fn>;
As `mp_any_of`, but takes a quoted metafunction.
## 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)`.
.Using mp_for_each and a C++14 lambda to print a tuple
```
template<class... T> void print( std::tuple<T...> const & tp )
{
std::size_t const N = sizeof...(T);
mp_for_each<mp_iota_c<N>>( [&]( auto I ){
// I is mp_size_t<0>, mp_size_t<1>, ..., mp_size_t<N-1>
std::cout << std::get<I>(tp) << std::endl;
});
}
```
In case the elements of the list `L` are not default-constructible, you can use
`mp_for_each<mp_transform<mp_identity, L>>`, which would call `f` with `mp_identity<T>()`
instead of `T()`.
## mp_with_index<N>(i, f)
template<std::size_t N, class F>
constexpr auto mp_with_index( std::size_t i, F && f )
-> decltype(std::declval<F>()(std::declval<mp_size_t<0>>()));
`mp_with_index<N>(i, f)` calls `f` with `mp_size_t<i>()` and returns the result. `i` must be less than `N`.
Only `constexpr` on C++14 and higher.
template<class N, class F>
constexpr auto mp_with_index( std::size_t i, F && f )
-> decltype(std::declval<F>()(std::declval<mp_size_t<0>>()));
Returns `mp_with_index<N::value>(i, f)`.
.Using mp_with_index and a C++14 lambda to print the active element of a variant
```
template<class... T> void print( std::variant<T...> const& v )
{
mp_with_index<sizeof...(T)>( v.index(), [&]( auto I ) {
// I is mp_size_t<v.index()>{} here
std::cout << std::get<I>( v ) << std::endl;
});
}
```

View File

@@ -0,0 +1,78 @@
////
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
////
[#bind]
# Bind, <boost/mp11/bind.hpp>
:toc:
:toc-title:
:idprefix:
## mp_arg<I>
template<std::size_t I> struct mp_arg;
`mp_arg<I>` is a quoted metafunction whose nested template `fn<T...>` returns the `I`-th zero-based element of `T...`.
## _1, ..., _9
using _1 = mp_arg<0>;
using _2 = mp_arg<1>;
using _3 = mp_arg<2>;
using _4 = mp_arg<3>;
using _5 = mp_arg<4>;
using _6 = mp_arg<5>;
using _7 = mp_arg<6>;
using _8 = mp_arg<7>;
using _9 = mp_arg<8>;
`_1` to `_9` are placeholder types, the equivalent to the placeholders of `boost::bind`.
## mp_bind<F, T...>
template<template<class...> class F, class... T> struct mp_bind;
`mp_bind<F, T...>` is a quoted metafunction that implements the type-based
equivalent of `boost::bind`. Its nested template `fn<U...>` returns `F<V...>`,
where `V...` is `T...` with the placeholders replaced by the corresponding
element of `U...` and the `mp_bind`, `mp_bind_front`, and `mp_bind_back`
expressions replaced with their corresponding evaluations against `U...`.
For example, `mp_bind<F, int, _2, mp_bind<G, _1>>::fn<float, void>` is `F<int, void, G<float>>`.
## mp_bind_q<Q, T...>
template<class Q, class... T> using mp_bind_q = mp_bind<Q::template fn, T...>;
As `mp_bind`, but takes a quoted metafunction.
## mp_bind_front<F, T...>
template<template<class...> class F, class... T> struct mp_bind_front;
`mp_bind_front<F, T...>` binds the leftmost arguments of `F` to `T...`. Its nested template `fn<U...>` returns `F<T..., U...>`.
## mp_bind_front_q<Q, T...>
template<class Q, class... T> using mp_bind_front_q =
mp_bind_front<Q::template fn, T...>;
As `mp_bind_front`, but takes a quoted metafunction.
## mp_bind_back<F, T...>
template<template<class...> class F, class... T> struct mp_bind_back;
`mp_bind_back<F, T...>` binds the rightmost arguments of `F` to `T...`. Its nested template `fn<U...>` returns `F<U..., T...>`.
## mp_bind_back_q<Q, T...>
template<class Q, class... T> using mp_bind_back_q =
mp_bind_back<Q::template fn, T...>;
As `mp_bind_back`, but takes a quoted metafunction.

View File

@@ -0,0 +1,54 @@
////
Copyright 2019-2020 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
////
[#changelog]
# Revision History
## Changes in 1.77.0
* Added `mp_intersperse`, `mp_split`, `mp_join`
## Changes in 1.75.0
* Added `mp_pairwise_fold` (suggested by Barry Revzin)
* Removed `mp_invoke` (use `mp_invoke_q`)
## Changes in 1.74.0
* Improved compilation performance of `mp_with_index<N>` for large `N`
* Added `tuple_transform` (contributed by Hans Dembinski)
## Changes in 1.73.0
* Added `mp_unique_if` (contributed by Kris Jusiak)
* Added `mp_flatten`
* Added `mp_rotate_left`, `mp_rotate_right` (contributed by Duncan Barber)
* Added `mp_compose`
* Added `mp_power_set`
* Added `mp_partial_sum`
* Added `mp_iterate`
## Changes in 1.70.0
* Renamed `mp_invoke` to `mp_invoke_q`
* Added `mp_similar`
* Added `mp_set_union`, `mp_set_intersection`, `mp_set_difference`
* Added `mp_not_fn`
* Added `mp_transform_first`, `mp_transform_second`, `mp_transform_third`
* Added `mp_filter`
* Added `mp_eval_if_not`, `mp_eval_or`, `mp_valid_q`
* Added `mp_back`, `mp_pop_back`
* Added `BOOST_MP11_VERSION`
## Changes in 1.69.0
* Removed dependency on Boost.Config; Mp11 is now standalone
* Improved code generation for `mp_with_index`
* Added `mp_starts_with` (contributed by Glen Fernandes)
* Added CMake support

View File

@@ -0,0 +1,53 @@
////
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
////
[#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`,
`std::is_const`, `mp_second`, `mp_push_front`, `mp_list`, `std::tuple`, `std::pair`, `std::shared_ptr`, or
```
template<class...> using F1 = void;
template<class T> using F2 = T*;
template<class... T> using F3 = std::integral_constant<std::size_t, sizeof...(T)>;
```
A _quoted metafunction_ is a class with a public metafunction member called `fn`, for example
```
struct Q1 { template<class...> using fn = void; };
struct Q2 { template<class T> using fn = T*; };
struct Q3 { template<class... T> using fn =
std::integral_constant<std::size_t, sizeof...(T)>; };
```
An _integral constant type_ is a class with a public member `value` that is an integral constant in the C++ sense. For example,
`std::integral_constant<int, 7>`, or
struct N { static int constexpr value = 2; };
A _set_ is a list whose elements are unique.
A _map_ is a list of lists, the inner lists having at least one element (the key.) The keys of the map must be unique. For example,
```
using M1 = std::tuple<std::pair<int, int*>, std::pair<float, float*>,
std::pair<void, void*>>;
using M2 = mp_list<mp_list<int, int*>, mp_list<float>,
mp_list<char, char[1], char[2]>>;
```

View File

@@ -0,0 +1,492 @@
////
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
////
[#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;
```
that ought to represent the result of an arithmetic operation on the integer types `T` and `U`,
for example `t + u`. We want to test whether `result<T, U>` gives correct results for various combinations
of `T` and `U`, so we write the function
```
template<class T1, class T2> void test_result()
{
using T3 = decltype( T1() + T2() );
using T4 = result<T1, T2>;
std::cout << ( std::is_same<T3, T4>::value? "[PASS]": "[FAIL]" ) << std::endl;
}
```
and then need to call it a substantial number of times:
int main()
{
test_result<char, char>();
test_result<char, short>();
test_result<char, int>();
test_result<char, unsigned>();
// ...
}
Writing all those type combinations by hand is unwieldy, error prone, and worst of all, boring. This is
how we can leverage Mp11 to automate the task:
```
#include <boost/mp11.hpp>
#include <boost/core/demangle.hpp>
#include <type_traits>
#include <iostream>
#include <typeinfo>
using namespace boost::mp11;
template<class T> std::string name()
{
return boost::core::demangle( typeid(T).name() );
}
template<class T> using promote = typename std::common_type<T, int>::type;
template<class T, class U> using result =
typename std::common_type<promote<T>, promote<U>>::type;
template<class T1, class T2> void test_result( mp_list<T1, T2> const& )
{
using T3 = decltype( T1() + T2() );
using T4 = result<T1, T2>;
std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " )
<< name<T1>() << " + " << name<T2>() << " -> " << name<T3>()
<< ", result: " << name<T4>() << std::endl;
}
int main()
{
using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
tuple_for_each( mp_product<mp_list, L, L>(), [](auto&& x){ test_result(x); } );
}
```
How does it work?
`mp_product<F, L1, L2>` calls `F<T1, T2>` where `T1` varies over the elements of `L1` and `T2` varies over
the elements of `L2`, as if by executing two nested loops. It then returns a list of these results, of the same
type as `L1`.
In our case, both lists are the same `std::tuple`, and `F` is `mp_list`, so `mp_product<mp_list, L, L>` will get us
`std::tuple<mp_list<char, char>, mp_list<char, short>, mp_list<char, int>, ..., mp_list<unsigned long, long>, mp_list<unsigned long, unsigned long>>`.
We then default-construct this tuple and pass it to `tuple_for_each`. `tuple_for_each(tp, f)` calls `f` for every
tuple element; we use a (C++14) lambda that calls `test_result`.
In pure C++11, we can't use a lambda with an `auto&&` parameter, so we'll have to make `test_result` a function object with
a templated `operator()` and pass that to `tuple_for_each` directly:
```
struct test_result
{
template<class T1, class T2> void operator()( mp_list<T1, T2> const& ) const
{
using T3 = decltype( T1() + T2() );
using T4 = result<T1, T2>;
std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " )
<< name<T1>() << " + " << name<T2>() << " -> " << name<T3>()
<< ", result: " << name<T4>() << std::endl;
}
};
int main()
{
using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
tuple_for_each( mp_product<mp_list, L, L>(), test_result() );
}
```
## Writing common_type Specializations
The standard trait `std::common_type`, used to obtain a type to which all of its arguments can convert without
unnecessary loss of precision, can be user-specialized when its default implementation (based on the ternary `?:`
operator) is unsuitable.
Let's write a `common_type` specialization for two `std::tuple` arguments. For that, we need a metafunction that
applies `std::common_type` to each pair of elements and gathers the results into a tuple:
```
template<class... T> using common_type_t =
typename std::common_type<T...>::type; // standard in C++14
template<class Tp1, class Tp2> using common_tuple =
mp_transform<common_type_t, Tp1, Tp2>;
```
then specialize `common_type` to use it:
```
namespace std
{
template<class... T1, class... T2>
struct common_type<std::tuple<T1...>, std::tuple<T2...>>:
mp_defer<common_tuple, std::tuple<T1...>, std::tuple<T2...>>
{
};
} // std
```
(There is no need to specialize `std::common_type` for more than two arguments - it takes care of synthesizing the appropriate semantics from
the binary case.)
The subtlety here is the use of `mp_defer`. We could have defined a nested `type` to `common_tuple<std::tuple<T1...>, std::tuple<T2...>>`,
and it would still have worked in all valid cases. By letting `mp_defer` define `type`, though, we make our specialization _SFINAE-friendly_.
That is, when our `common_tuple` causes a substitution failure instead of a hard error, `mp_defer` will not define a nested `type`,
and `common_type_t`, which is defined as `typename common_type<...>::type`, will also cause a substitution failure.
As another example, consider the hypothetical type `expected<T, E...>` that represents either a successful return with a value of `T`,
or an unsuccessful return with an error code of some type in the list `E...`. The common type of `expected<T1, E1, E2, E3>` and
`expected<T2, E1, E4, E5>` is `expected<common_type_t<T1, T2>, E1, E2, E3, E4, E5>`. That is, the possible return values are
combined into their common type, and we take the union of the set of error types.
Therefore,
```
template<class T1, class E1, class T2, class E2> using common_expected =
mp_rename<mp_push_front<mp_unique<mp_append<E1, E2>>, common_type_t<T1, T2>>,
expected>;
namespace std
{
template<class T1, class... E1, class T2, class... E2>
struct common_type<expected<T1, E1...>, expected<T2, E2...>>:
mp_defer<common_expected, T1, mp_list<E1...>, T2, mp_list<E2...>>
{
};
} // std
```
Here we've taken a different tack; instead of passing the `expected` types to `common_expected`, we're passing the `T` types and lists of
the `E` types. This makes our job easier. `mp_unique<mp_append<E1, E2>>` gives us the concatenation of `E1` and `E2` with the duplicates
removed; we then add `common_type_t<T1, T2>` to the front via `mp_push_front`; and finally, we `mp_rename` the resultant `mp_list`
to `expected`.
## Fixing tuple_cat
The article http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html#[Simple C++11 metaprogramming] builds an
implementation of the standard function `tuple_cat`, with the end result given below:
```
template<class L> using F = mp_iota<mp_size<L>>;
template<class R, class...Is, class... Ks, class Tp>
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,
class R = mp_append<std::tuple<>, typename std::remove_reference<Tp>::type...>>
R tuple_cat( Tp &&... tp )
{
std::size_t const N = sizeof...(Tp);
// inner
using list1 = mp_list<
mp_rename<typename std::remove_reference<Tp>::type, mp_list>...>;
using list2 = mp_iota_c<N>;
using list3 = mp_transform<mp_fill, list1, list2>;
using inner = mp_apply<mp_append, list3>;
// outer
using list4 = mp_transform<F, list1>;
using outer = mp_apply<mp_append, list4>;
//
return tuple_cat_<R>( inner(), outer(),
std::forward_as_tuple( std::forward<Tp>(tp)... ) );
}
```
This function, however, is not entirely correct, in that it doesn't handle some cases properly. For example,
trying to concatenate tuples containing move-only elements such as `unique_ptr` fails:
```
std::tuple<std::unique_ptr<int>> t1;
std::tuple<std::unique_ptr<float>> t2;
auto result = ::tuple_cat( std::move( t1 ), std::move( t2 ) );
```
Trying to concatenate `const` tuples fails:
```
std::tuple<int> const t1;
std::tuple<float> const t2;
auto result = ::tuple_cat( t1, t2 );
```
And finally, the standard `tuple_cat` is specified to work on arbitrary tuple-like types (that is, all types
that support `tuple_size`, `tuple_element`, and `get`), while our implementation only works with `tuple` and
`pair`. `std::array`, for example, fails:
```
std::array<int, 2> t1{ 1, 2 };
std::array<float, 3> t2{ 3.0f, 4.0f, 5.0f };
auto result = ::tuple_cat( t1, t2 );
```
Let's fix these one by one. Support for move-only types is easy, if one knows where to look. The problem is
that `Tp` that we're passing to the helper `tuple_cat_` is (correctly) `tuple<unique_ptr<int>&&, unique_ptr<float>&&>`,
but `std::get<0>(tp)` still returns `unique_ptr<int>&`, because `tp` is an lvalue. This behavior is a bit
surprising, but is intended to prevent inadvertent double moves.
Long story short, we need `std::move(tp)` in `tuple_cat_` to make `tp` an rvalue:
template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
}
Next, `const`-qualified tuples. The issue here is that we're stripping references from the input tuples, but not
`const`. As a result, we're trying to manipulate types such as `tuple<int> const` with Mp11 algorithms, and these
types do not fit the list concept. We just need to strip qualifiers as well, by defining the useful `remove_cv_ref`
primitive that is inexplicably missing from the standard library:
template<class T> using remove_cv_ref = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
and then by using `remove_cv_ref<Tp>` in place of `typename std::remove_reference<Tp>::type`:
```
template<class... Tp,
class R = mp_append<std::tuple<>, remove_cv_ref<Tp>...>>
R tuple_cat( Tp &&... tp )
{
std::size_t const N = sizeof...(Tp);
// inner
using list1 = mp_list<mp_rename<remove_cv_ref<Tp>, mp_list>...>;
// ...
```
Finally, tuple-like types. We've so far exploited the fact that `std::pair` and `std::tuple` are valid Mp11 lists,
but in general, arbitrary tuple-like types aren't, so we need to convert them into such. For that, we'll need to
define a metafunction `from_tuple_like` that will take an arbitrary tuple-like type and will return, in our case,
the corresponding `mp_list`.
Technically, a more principled approach would've been to return `std::tuple`, but here `mp_list` will prove more
convenient.
What we need is, given a tuple-like type `Tp`, to obtain `mp_list<std::tuple_element<0, Tp>::type, std::tuple_element<1, Tp>::type,
..., std::tuple_element<N-1, Tp>::type>`, where `N` is `tuple_size<Tp>::value`. Here's one way to do it:
```
template<class T, class I> using tuple_element =
typename std::tuple_element<I::value, T>::type;
template<class T> using from_tuple_like =
mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
```
(`mp_iota<N>` is an algorithm that returns an `mp_list` with elements `mp_size_t<0>`, `mp_size_t<1>`, ..., `mp_size_t<N-1>`.)
Remember that `mp_product<F, L1, L2>` performs the equivalent of two nested loops over the elements of `L1` and `L2`,
applying `F` to the two variables and gathering the result. In our case `L1` consists of the single element `T`, so
only the second loop (over `mp_iota<N>`, where `N` is `tuple_size<T>`), remains, and we get a list of the same type
as `L1` (an `mp_list`) with contents `tuple_element<T, mp_size_t<0>>`, `tuple_element<T, mp_size_t<1>>`, ...,
`tuple_element<T, mp_size_t<N-1>>`.
For completeness's sake, here's another, more traditional way to achieve the same result:
template<class T> using from_tuple_like =
mp_transform_q<mp_bind_front<tuple_element, T>, mp_iota<std::tuple_size<T>>>;
With all these fixes applied, our fully operational `tuple_cat` now looks like this:
```
template<class L> using F = mp_iota<mp_size<L>>;
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<
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... 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
using list1 = mp_list<from_tuple_like<remove_cv_ref<Tp>>...>;
using list2 = mp_iota_c<N>;
using list3 = mp_transform<mp_fill, list1, list2>;
using inner = mp_apply<mp_append, list3>;
// outer
using list4 = mp_transform<F, list1>;
using outer = mp_apply<mp_append, list4>;
//
return tuple_cat_<R>( inner(), outer(),
std::forward_as_tuple( std::forward<Tp>(tp)... ) );
}
```
## Computing Return Types
{cpp}17 has a standard variant type, called `std::variant`. It also defines a function template
`std::visit` that can be used to apply a function to the contained value of one or more variants.
So for instance, if the variant `v1` contains `1`, and the variant `v2` contains `2.0f`,
`std::visit(f, v1, v2)` will call `f(1, 2.0f)`.
However, `std::visit` has one limitation: it cannot return a result unless all
possible applications of the function have the same return type. If, for instance, `v1` and `v2`
are both of type `std::variant<short, int, float>`,
std::visit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
will fail to compile because the result of `x + y` can be either `int` or `float` depending on
what `v1` and `v2` hold.
A type that can hold either `int` or `float` already exists, called, surprisingly enough, `std::variant<int, float>`.
Let's write our own function template `rvisit` that is the same as `visit` but returns a `variant`:
```
template<class F, class... V> auto rvisit( F&& f, V&&... v )
{
using R = /*...*/;
return std::visit( [&]( auto&&... x )
{ return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); },
std::forward<V>( v )... );
}
```
What this does is basically calls `std::visit` to do the work, but instead of passing it `f`, we pass a lambda that does the same as `f` except
it converts the result to a common type `R`. `R` is supposed to be `std::variant<...>` where the ellipsis denotes the return types of
calling `f` with all possible combinations of variant values.
We'll first define a helper quoted metafunction `Qret<F>` that returns the result of the application of `F` to arguments of type `T...`:
template<class F> struct Qret
{
template<class... T> using fn =
decltype( std::declval<F>()( std::declval<T>()... ) );
};
It turns out that {cpp}17 already contains a metafunction that returns the result of the application of a function `F` to arguments
of type `T...`: `std::invoke_result_t<F, T...>`. We can make use of it to simplify our `Qret` to
template<class F> struct Qret
{
template<class... T> using fn = std::invoke_result_t<F, T...>;
};
which in Mp11 can be expressed more concisely as
using Qret = mp_bind_front<std::invoke_result_t, F>;
With `Qret` in hand, a `variant` of the possible return types is just a matter of applying it over the possible combinations of the variant values:
using R = mp_product_q<Qret, remove_cv_ref<V>...>;
Why does this work? `mp_product<F, L1<T1...>, L2<T2...>, ..., Ln<Tn...>>` returns `L1<F<U1, U2, ..., Un>, ...>`, where `Ui` traverse all
possible combinations of list values. Since in our case all `Li` are `std::variant`, the result will also be `std::variant`. (`mp_product_q` is
the same as `mp_product`, but for quoted metafunctions such as our `Qret`.)
One more step remains. Suppose that, as above, we're passing two variants of type `std::variant<short, int, float>` and `F` is
`[]( auto const& x, auto const& y ){ return x + y; }`. This will generate `R` of length 9, one per each combination, but many of those
elements will be the same, either `int` or `float`, and we need to filter out the duplicates. So, we pass the result to `mp_unique`:
using R = mp_unique<mp_product_q<Qret, remove_cv_ref<V>...>>;
and we're done:
```
#include <boost/mp11.hpp>
#include <boost/core/demangle.hpp>
#include <variant>
#include <type_traits>
#include <typeinfo>
#include <iostream>
using namespace boost::mp11;
template<class T> using remove_cv_ref = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
template<class F, class... V> auto rvisit( F&& f, V&&... v )
{
using Qret = mp_bind_front<std::invoke_result_t, F>;
using R = mp_unique<mp_product_q<Qret, remove_cv_ref<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 boost::core::demangle( typeid(T).name() );
}
template<class V> void print_variant( char const * n, V const& v )
{
std::cout << "(" << name<decltype(v)>() << ")" << n << ": ";
std::visit( []( auto const& x )
{ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v );
}
int main()
{
std::variant<char, int, float> v1( 1 );
print_variant( "v1", v1 );
std::variant<short, int, double> const v2( 3.14 );
print_variant( "v2", v2 );
auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
print_variant( "v3", v3 );
}
```

View File

@@ -0,0 +1,152 @@
////
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
////
[#function]
# Helper Metafunctions, <boost/mp11/function.hpp>
:toc:
:toc-title:
:idprefix:
## mp_void<T...>
template<class... T> using mp_void = void;
Same as `std::void_t` from C++17.
## mp_and<T...>
template<class... T> using mp_and = /*...*/;
`mp_and<T...>` applies `mp_to_bool` to the types in `T...`, in order. If the result of an application is `mp_false`, `mp_and`
returns `mp_false`. If the application causes a substitution failure, returns `mp_false`. If all results are `mp_true`,
returns `mp_true`. `mp_and<>` is `mp_true`.
.mp_and behavior
```
using R1 = mp_and<mp_true, mp_true>; // mp_true
using R2 = mp_and<mp_false, void>; // mp_false, void is not reached
using R3 = mp_and<mp_false, mp_false>; // mp_false
using R4 = mp_and<void, mp_true>; // mp_false (!)
```
## mp_all<T...>
template<class... T> using mp_all = /*...*/;
`mp_all<T...>` is `mp_true` if `mp_to_bool<U>` is `mp_true` for all types `U` in `T...`, `mp_false` otherwise. Same as
`mp_and`, but does not perform short-circuit evaluation. `mp_and<mp_false, void>` is `mp_false`, but `mp_all<mp_false, void>`
is an error because `void` does not have a nested `value`. The upside is that `mp_all` is potentially faster and does not
mask substitution failures as `mp_and` does.
.mp_all behavior
```
using R1 = mp_all<mp_true, mp_true>; // mp_true
using R2 = mp_all<mp_false, void>; // compile-time error
using R3 = mp_all<mp_false, mp_false>; // mp_false
using R4 = mp_all<void, mp_true>; // compile-time error
```
## mp_or<T...>
template<class... T> using mp_or = /*...*/;
`mp_or<T...>` applies `mp_to_bool` to the types in `T...`, in order. If the result of an application is `mp_true`, `mp_or`
returns `mp_true`. If all results are `mp_false`, returns `mp_false`. `mp_or<>` is `mp_false`.
.mp_or behavior
```
using R1 = mp_or<mp_true, mp_false>; // mp_true
using R2 = mp_or<mp_true, void>; // mp_true, void is not reached
using R3 = mp_or<mp_false, mp_false>; // mp_false
using R4 = mp_or<void, mp_true>; // compile-time error
```
## mp_any<T...>
template<class... T> using mp_any = /*...*/;
`mp_any<T...>` is `mp_true` if `mp_to_bool<U>` is `mp_true` for any type `U` in `T...`, `mp_false` otherwise. Same as
`mp_or`, but does not perform short-circuit evaluation.
.mp_any behavior
```
using R1 = mp_any<mp_true, mp_false>; // mp_true
using R2 = mp_any<mp_true, void>; // compile-time error
using R3 = mp_any<mp_false, mp_false>; // mp_false
using R4 = mp_any<void, mp_true>; // compile-time error
```
## mp_same<T...>
template<class... T> using mp_same = /*...*/;
`mp_same<T...>` is `mp_true` if all the types in `T...` are the same type, `mp_false` otherwise. `mp_same<>` is `mp_true`.
## mp_similar<T...>
template<class... T> using mp_similar = /*...*/;
`mp_similar<T...>` is `mp_true` if all the types in `T...` are the same type, or instantiations of the same class template
whose parameters are all types, `mp_false` otherwise. `mp_similar<>` is `mp_true`.
.mp_similar
```
using R1 = mp_similar<void>; // mp_true
using R2 = mp_similar<void, void>; // mp_true
using R3 = mp_similar<void, void, void>; // mp_true
using R4 = mp_similar<void, void, float>; // mp_false
template<class T> struct X;
template<class... T> struct Y;
using R5 = mp_similar<X<int>, X<void>, X<float>>; // mp_true
using R6 = mp_similar<Y<>, Y<void>, Y<void, void>>; // mp_true
using R7 = mp_similar<X<void>, Y<void>>; // mp_false
```
## 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>`.
## mp_less<T1, T2>
template<class T1, class T2> using mp_less = /*...*/;
`mp_less<T1, T2>` is `mp_true` when the numeric value of `T1::value` is less than the numeric value of `T2::value`,
`mp_false` otherwise.
(Note that this is not necessarily the same as `T1::value < T2::value` when comparing between signed and unsigned types;
`-1 < 1u` is `false`, but `mp_less<mp_int\<-1>, mp_size_t<1>>` is `mp_true`.)
## mp_min<T1, T...>
template<class T1, class... T> using mp_min = mp_min_element<mp_list<T1, T...>, mp_less>;
`mp_min<T...>` returns the type `U` in `T...` with the lowest `U::value`.
## mp_max<T1, T...>
template<class T1, class... T> using mp_max = mp_max_element<mp_list<T1, T...>, mp_less>;
`mp_max<T...>` returns the type `U` in `T...` with the highest `U::value`.

View File

@@ -0,0 +1,48 @@
////
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
////
[#integer_sequence]
# Integer Sequences, <boost/mp11/integer_sequence.hpp>
:toc:
:toc-title:
:idprefix:
## integer_sequence<T, I...>
template<class T, T... I> struct integer_sequence
{
};
`integer_sequence<T, I...>` holds a sequence of integers of type `T`. Same as C++14's `std::integer_sequence`.
## make_integer_sequence<T, N>
template<class T, T N> using make_integer_sequence = /*...*/;
`make_integer_sequence<T, N>` is `integer_sequence<T, 0, 1, ..., N-1>`. Same as C++14's `std::make_integer_sequence`.
## index_sequence<I...>
template<std::size_t... I> using index_sequence = integer_sequence<std::size_t, I...>;
`index_sequence<I...>` is an alias for `integer_sequence<size_t, I...>`. Same as C++14's `std::index_sequence`.
## make_index_sequence<N>
template<std::size_t N> using make_index_sequence =
make_integer_sequence<std::size_t, N>;
`make_index_sequence<N>` is `index_sequence<0, 1, ..., N-1>`. Same as C++14's `std::make_index_sequence`.
## index_sequence_for<T...>
template<class... T> using index_sequence_for =
make_integer_sequence<std::size_t, sizeof...(T)>;
`index_sequence_for<N>` is `make_index_sequence<sizeof...(T)>`. Same as C++14's `std::index_sequence_for`.

View File

@@ -0,0 +1,50 @@
////
Copyright 2017 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt
////
[#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.
## mp_bool<B>
template<bool B> using mp_bool = std::integral_constant<bool, B>;
Same as `std::bool_constant` in C++17.
## mp_true
using mp_true = mp_bool<true>;
Same as `std::true_type`.
## mp_false
using mp_false = mp_bool<false>;
Same as `std::false_type`.
## mp_to_bool<T>
template<class T> using mp_to_bool = mp_bool<static_cast<bool>(T::value)>;
## mp_not<T>
template<class T> using mp_not = mp_bool< !T::value >;
## mp_int<I>
template<int I> using mp_int = std::integral_constant<int, I>;
## mp_size_t<N>
template<std::size_t N> using mp_size_t = std::integral_constant<std::size_t, N>;

View File

@@ -0,0 +1,443 @@
////
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
////
[#list]
# List Operations, <boost/mp11/list.hpp>
:toc:
:toc-title:
:idprefix:
## mp_list<T...>
template<class... T> struct mp_list {};
`mp_list` is the standard list type of Mp11, although the library is not restricted to it and can operate on arbitrary class templates
such as `std::tuple` or `std::variant`. Even `std::pair` can be used if the transformation does not alter the number of the elements in
the list.
## mp_list_c<T, I...>
template<class T, T... I> using mp_list_c =
mp_list<std::integral_constant<T, I>...>;
`mp_list_c` produces an `mp_list` of the `std::integral_constant` types corresponding to its integer template arguments.
.Using mp_list_c
```
using L1 = mp_list_c<int, 2, 3>; // mp_list<mp_int<2>, mp_int<3>>
```
## mp_is_list<L>
template<class L> using mp_is_list = /*...*/;
`mp_is_list<L>` is `mp_true` if `L` is a list (an instantiation of a class template whose template parameters are types), `mp_false` otherwise.
## 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 mp_size with mp_list
```
using L1 = mp_list<>;
using R1 = mp_size<L1>; // mp_size_t\<0>
```
.Using mp_size with std::pair
```
using L2 = std::pair<int, int>;
using R2 = mp_size<L2>; // mp_size_t\<2>
```
.Using mp_size with std::tuple
```
using L3 = std::tuple<float>;
using R3 = mp_size<L3>; // mp_size_t\<1>
```
## mp_empty<L>
template<class L> using mp_empty = mp_bool<mp_size<L>::value == 0>;
`mp_empty<L>` is an alias for `mp_true` if the list `L` is empty, for `mp_false` otherwise.
.Using mp_empty with std::tuple
```
using L1 = std::tuple<float>;
using R1 = mp_empty<L1>; // mp_false
using L2 = std::tuple<>;
using R2 = mp_empty<L2>; // mp_true
```
## 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`.
.Using mp_assign with mp_list and std::tuple
```
using L1 = std::tuple<long>;
using L2 = mp_list<int, float>;
using R1 = mp_assign<L1, L2>; // std::tuple<int, float>
```
.Using mp_assign with mp_list and std::pair
```
using L1 = std::pair<long, char>;
using L2 = mp_list<int, float>;
using R1 = mp_assign<L1, L2>; // std::pair<int, float>
```
## 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`.
.Using mp_clear with std::tuple
```
using L1 = std::tuple<int, float>;
using R1 = mp_clear<L1>; // std::tuple<>
```
## mp_front<L>
template<class L> using mp_front = /*...*/;
`mp_front<L>` is the first element of the list `L`. That is, `mp_front<L<T1, T...>>` is an alias for `T1`.
.Using mp_front with std::pair
```
using L1 = std::pair<int, float>;
using R1 = mp_front<L1>; // int
```
.Using mp_front with std::tuple
```
using L2 = std::tuple<float, double, long double>;
using R2 = mp_front<L2>; // float
```
.Using mp_front with mp_list
```
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_front<L3>; // char[1]
```
## mp_pop_front<L>
template<class L> using mp_pop_front = /*...*/;
`mp_pop_front<L>` removes the first element of the list `L`. That is, `mp_pop_front<L<T1, T...>>` is an alias for `L<T...>`.
.Using mp_pop_front with std::tuple
```
using L1 = std::tuple<float, double, long double>;
using R1 = mp_pop_front<L1>; // std::tuple<double, long double>
```
.Using mp_pop_front with mp_list
```
using L2 = mp_list<void>;
using R2 = mp_pop_front<L2>; // mp_list<>
```
## mp_first<L>
template<class L> using mp_first = mp_front<L>;
`mp_first` is another name for `mp_front`.
## mp_rest<L>
template<class L> using mp_rest = mp_pop_front<L>;
`mp_rest` is another name for `mp_pop_front`.
## mp_second<L>
template<class L> using mp_second = /*...*/;
`mp_second<L>` is the second element of the list `L`. That is, `mp_second<L<T1, T2, T...>>` is an alias for `T2`.
.Using mp_second with std::pair
```
using L1 = std::pair<int, float>;
using R1 = mp_second<L1>; // float
```
.Using mp_second with std::tuple
```
using L2 = std::tuple<float, double, long double>;
using R2 = mp_second<L2>; // double
```
.Using mp_second with mp_list
```
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_second<L3>; // char[2]
```
## mp_third<L>
template<class L> using mp_third = /*...*/;
`mp_third<L>` is the third element of the list `L`. That is, `mp_third<L<T1, T2, T3, T...>>` is an alias for `T3`.
.Using mp_third with std::tuple
```
using L1 = std::tuple<float, double, long double>;
using R1 = mp_third<L1>; // long double
```
.Using mp_third with mp_list
```
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
using R2 = mp_third<L2>; // char[3]
```
## mp_push_front<L, T...>
template<class L, class... T> using mp_push_front = /*...*/;
`mp_push_front<L, T...>` inserts the elements `T...` at the front of the list `L`. That is, `mp_push_front<L<U...>, T...>`
is an alias for `L<T..., U...>`.
.Using mp_push_front with std::tuple
```
using L1 = std::tuple<double, long double>;
using R1 = mp_push_front<L1, float>; // std::tuple<float, double, long double>
```
.Using mp_push_front with mp_list
```
using L2 = mp_list<void>;
using R2 = mp_push_front<L2, char[1], char[2]>; // mp_list<char[1], char[2], void>
```
## mp_push_back<L, T...>
template<class L, class... T> using mp_push_back = /*...*/;
`mp_push_back<L, T...>` inserts the elements `T...` at the back of the list `L`. That is, `mp_push_back<L<U...>, T...>`
is an alias for `L<U..., T...>`.
.Using mp_push_back with std::tuple
```
using L1 = std::tuple<double, long double>;
using R1 = mp_push_back<L1, float>; // std::tuple<double, long double, float>
```
.Using mp_push_back with mp_list
```
using L2 = mp_list<void>;
using R2 = mp_push_back<L2, char[1], char[2]>; // mp_list<void, char[1], char[2]>
```
## mp_rename<L, Y>
template<class L, template<class...> class Y> using mp_rename = /*...*/;
`mp_rename<L, Y>` changes the type of the list `L` to `Y`. That is, `mp_rename<L<T...>, Y>` is an alias for `Y<T...>`.
.Using mp_rename to rename std::pair to std::tuple
```
using L1 = std::pair<double, long double>;
using R1 = mp_rename<L1, std::tuple>; // std::tuple<double, long double>
```
.Using mp_rename to rename std::tuple to mp_list
```
using L2 = std::tuple<void>;
using R2 = mp_rename<L2, mp_list>; // mp_list<void>
```
## mp_apply<F, L>
template<template<class...> class F, class L> using mp_apply = mp_rename<L, F>;
`mp_apply<F, L>` applies the metafunction `F` to the contents of the list `L`, that is, `mp_apply<F, L<T...>>` is an alias for `F<T...>`.
(`mp_apply` is the same as `mp_rename` with the arguments reversed.)
.Using mp_apply with std::pair
```
using L1 = std::pair<double, long double>;
using R1 = mp_apply<std::is_same, L1>; // std::is_same<double, long double>
```
## mp_apply_q<Q, L>
template<class Q, class L> using mp_apply_q = mp_apply<Q::template fn, L>;
Same as `mp_apply`, but takes a quoted metafunction.
.Using mp_apply_q with mp_bind_front
```
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>;
// R1 is std::tuple<double, long double, int, long>
```
## mp_append<L...>
template<class... L> using mp_append = /*...*/;
`mp_append<L...>` concatenates the lists in `L...` into a single list that has the same type as the first list. `mp_append<>`
is an alias for `mp_list<>`. `mp_append<L1<T1...>, L2<T2...>, ..., Ln<Tn...>>` is an alias for `L1<T1..., T2..., ..., Tn...>`.
.Using mp_append with lists of various types
```
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>
template<class L, class T> using mp_replace_front = /*...*/;
`mp_replace_front<L, T>` replaces the first element of the list `L` with `T`. That is, `mp_replace_front<L<U1, U...>, T>` is
an alias for `L<T, U...>`.
.Using mp_replace_front with std::pair
```
using L1 = std::pair<int, float>;
using R1 = mp_replace_front<L1, void>; // std::pair<void, float>
```
.Using mp_replace_front with std::tuple
```
using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_front<L2, void>; // std::tuple<void, double, long double>
```
.Using mp_replace_front with mp_list
```
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_replace_front<L3, void>; // mp_list<void, char[2], char[3], char[4]>;
```
## mp_replace_first<L, T>
template<class L, class T> using mp_replace_first = mp_replace_front<L, T>;
`mp_replace_first` is another name for `mp_replace_front`.
## mp_replace_second<L, T>
template<class L, class T> using mp_replace_second = /*...*/;
`mp_replace_second<L, T>` replaces the second element of the list `L` with `T`. That is, `mp_replace_second<L<U1, U2, U...>, T>`
is an alias for `L<U1, T, U...>`.
.Using mp_replace_second with std::pair
```
using L1 = std::pair<int, float>;
using R1 = mp_replace_second<L1, void>; // std::pair<int, void>
```
.Using mp_replace_second with std::tuple
```
using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_second<L2, void>; // std::tuple<float, void, long double>
```
.Using mp_replace_front with mp_list
```
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_replace_second<L3, void>; // mp_list<char[1], void, char[3], char[4]>;
```
## mp_replace_third<L, T>
template<class L, class T> using mp_replace_third = /*...*/;
`mp_replace_third<L, T>` replaces the third element of the list `L` with `T`. That is, `mp_replace_third<L<U1, U2, U3, U...>, T>`
is an alias for `L<U1, U2, T, U...>`.
.Using mp_replace_third with std::tuple
```
using L1 = std::tuple<float, double, long double>;
using R1 = mp_replace_third<L1, void>; // std::tuple<float, double, void>
```
.Using mp_replace_third with mp_list
```
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]>;
```
## mp_transform_front<L, F>
template<class L, template<class...> class F> using mp_transform_front =
/*...*/;
`mp_transform_front<L, F>` replaces the first element `T1` of the list `L` with `F<T1>`.
## mp_transform_front_q<L, Q>
template<class L, class Q> using mp_transform_front_q =
mp_transform_front<L, Q::template fn>;
As `mp_transform_front`, but takes a quoted metafunction.
## mp_transform_first<L, F>
template<class L, template<class...> class F> using mp_transform_first =
mp_transform_front<L, F>;
`mp_transform_first` is another name for `mp_transform_front`.
## mp_transform_first_q<L, Q>
template<class L, class Q> using mp_transform_first_q =
mp_transform_first<L, Q::template fn>;
As `mp_transform_first`, but takes a quoted metafunction.
## mp_transform_second<L, F>
template<class L, template<class...> class F> using mp_transform_second =
/*...*/;
`mp_transform_second<L, F>` replaces the second element `T2` of the list `L` with `F<T2>`.
## mp_transform_second_q<L, Q>
template<class L, class Q> using mp_transform_second_q =
mp_transform_second<L, Q::template fn>;
As `mp_transform_second`, but takes a quoted metafunction.
## mp_transform_third<L, F>
template<class L, template<class...> class F> using mp_transform_third =
/*...*/;
`mp_transform_third<L, F>` replaces the third element `T3` of the list `L` with `F<T3>`.
## mp_transform_third_q<L, Q>
template<class L, class Q> using mp_transform_third_q =
mp_transform_third<L, Q::template fn>;
As `mp_transform_third`, but takes a quoted metafunction.

View File

@@ -0,0 +1,88 @@
////
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
////
[#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.
## mp_is_map<M>
template<class M> using mp_is_map = /*...*/;
`mp_is_map<M>` is `mp_true` if `M` is a map, `mp_false` otherwise.
## mp_map_find<M, K>
template<class M, class K> using mp_map_find = /*...*/;
`mp_map_find<M, K>` is an alias for the element of the map `M` with a key `K`, or for `void`, if there is no such element.
## mp_map_contains<M, K>
template<class M, class K> using mp_map_contains =
mp_not<std::is_same<mp_map_find<M, K>, void>>;
`mp_map_contains<M, K>` is `mp_true` if the map `M` contains an element with a key `K`, `mp_false` otherwise.
## mp_map_insert<M, T>
template<class M, class T> using mp_map_insert =
mp_if< mp_map_contains<M, mp_first<T>>, M, mp_push_back<M, T> >;
Inserts the element `T` into the map `M`, if an element with a key `mp_first<T>` is not already in `M`.
## mp_map_replace<M, T>
template<class M, class T> using mp_map_replace = /*...*/;
If the map `M` does not contain an element with a key `mp_first<T>`, inserts it (using `mp_push_back<M, T>`); otherwise,
replaces the existing element with `T`.
## mp_map_update<M, T, F>
template<class M, class T, template<class...> class F> using mp_map_update = /*...*/;
If the map `M` does not contain an element with a key `mp_first<T>`, inserts it (using `mp_push_back<M, T>`); otherwise,
replaces the existing element `L<X, Y...>` with `L<X, F<X, Y...>>`.
.Using mp_map_update to count the number of occurrences of types in a list
```
template<class T, class U> using inc2nd = mp_int<U::value + 1>;
template<class M, class T> using count_types =
mp_map_update<M, std::pair<T, mp_int<1>>, inc2nd>;
using L1 = mp_list<float, char, float, float, float, float, char, float>;
using R1 = mp_fold<L1, std::tuple<>, count_types>;
// std::tuple<std::pair<float, mp_int<6>>, std::pair<char, mp_int<2>>>
```
## mp_map_update_q<M, T, Q>
template<class M, class T, class Q> using mp_map_update_q =
mp_map_update<M, T, Q::template fn>;
As `mp_map_update`, but takes a quoted metafunction.
## 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.
## mp_map_keys<M>
template<class M> using mp_map_keys = mp_transform<mp_first, M>;
`mp_map_keys<M>` returns a list of the keys of `M`. When `M` is a valid map, the keys are unique, so the result is a set.

View File

@@ -0,0 +1,17 @@
////
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
////
[#mp11]
# Convenience Header, <boost/mp11.hpp>
:toc:
:toc-title:
:idprefix:
The convenience header `<boost/mp11.hpp>` includes all of the
headers listed previously in this reference.

View File

@@ -0,0 +1,31 @@
////
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
////
[#mpl]
# MPL Support, <boost/mp11/mpl.hpp>
:toc:
:toc-title:
:idprefix:
The header `<boost/mp11/mpl.hpp>`, when included, defines the
necessary support infrastructure for `mp_list` and `std::tuple`
to be valid link:../../../../libs/mpl[MPL] sequences.
NOTE: `mpl.hpp` is not included by `<boost/mp11.hpp>`.
It's also possible to only enable support for `mp_list` by
including `<boost/mp11/mpl_list.hpp>`, and for `std::tuple`
by including `<boost/mp11/mpl_tuple.hpp>`. This may be required
because some libraries, such as Boost.Fusion, contain their own MPL
support for `std::tuple`, which conflicts with Mp11's one.
.Converting an existing MPL Sequence into an mp_list
```
using L = mpl::copy<Sequence, mpl::back_inserter<mp11::mp_list<>>>::type;
```

View File

@@ -0,0 +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
////
[#overview]
# Overview
Mp11 is a C++11 metaprogramming library for compile-time manipulation of data structures
that contain types. It's based on template aliases and variadic templates and implements the
approach outlined in the article
<<simple_cxx11_metaprogramming.adoc#,"Simple {cpp} metaprogramming">>
and <<simple_cxx11_metaprogramming_2.adoc#,its sequel>>. Reading these
articles before proceeding with this documentation is _highly_ recommended.
The general principles upon which Mp11 is built are that algorithms and metafunctions are
template aliases of the form `F<T...>` and data structures are lists of the form `L<T...>`,
with the library placing no requirements on `L`. `mp_list<T...>` is the built-in list type,
but `std::tuple<T...>`, `std::pair<T1, T2>` and `std::variant<T...>` are also perfectly
legitimate list types, although of course `std::pair<T1, T2>`, due to having exactly two elements,
is not resizeable and will consequently not work with algorithms that need to add or remove
elements.
Another distinguishing feature of this approach is that lists (`L<T...>`) have the same form as
metafunctions (`F<T...>`) and can therefore be used as such. For example, applying `std::add_pointer_t`
to the list `std::tuple<int, float>` by way of `mp_transform<std::add_pointer_t, std::tuple<int, float>>`
gives us `std::tuple<int*, float*>`, but we can also apply `mp_list` to the same tuple:
using R = mp_transform<mp_list, std::tuple<int, float>>;
and get `std::tuple<mp_list<int>, mp_list<float>>`.

View File

@@ -0,0 +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
////
[#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.adoc[]
include::mp11.adoc[]
include::mpl.adoc[]
:leveloffset: -1

View File

@@ -0,0 +1,61 @@
////
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
////
[#set]
# Set Operations, <boost/mp11/set.hpp>
:toc:
:toc-title:
:idprefix:
A set is a list whose elements are unique.
## mp_is_set<S>
template<class S> using mp_is_set = /*...*/;
`mp_is_set<S>` is `mp_true` if `S` is a set, `mp_false` otherwise.
## mp_set_contains<S, V>
template<class S, class V> using mp_set_contains = /*...*/;
`mp_set_contains<S, V>` is `mp_true` if the type `V` is an element of the set `S`, `mp_false` otherwise.
## mp_set_push_back<S, T...>
template<class S, class... T> using mp_set_push_back = /*...*/;
For each `T1` in `T...`, `mp_set_push_back<S, T...>` appends `T1` to the end of the set `S` if it's not already an element of `S`.
## mp_set_push_front<S, T...>
template<class S, class... T> using mp_set_push_front = /*...*/;
`mp_set_push_front<S, T...>` inserts at the front of the set `S` those elements of `T...` for which `S` does not already contain the same type.
## mp_set_union<L...>
template<class... L> using mp_set_union = /*...*/;
`mp_set_union<S, L...>` is `mp_set_push_back<S, T...>`, where `T...` are the combined elements of the lists `L...`.
`mp_set_union<>` is `mp_list<>`.
## mp_set_intersection<S...>
template<class... S> using mp_set_intersection = /*...*/;
`mp_set_intersection<S...>` returns a set that contains the elements that occur in all of the sets `S...`.
`mp_set_intersection<>` is `mp_list<>`.
## mp_set_difference<L, S...>
template<class L, class... S> using mp_set_difference = /*...*/;
`mp_set_difference<L, S...>` removes the elements of the list `L` that appear in any of the sets `S...` and
returns the result.

View File

@@ -0,0 +1,55 @@
////
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]
# Tuple Operations, <boost/mp11/tuple.hpp>
:toc:
:toc-title:
:idprefix:
## tuple_apply(f, tp)
template<class F, class Tp> constexpr /*...*/ tuple_apply(F&& f, Tp&& tp);
`tuple_apply(f, tp)` returns `std::forward<F>(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`. Same as `std::apply` in C++17.
## construct_from_tuple<T>(tp)
template<class T, class Tp> T construct_from_tuple(Tp&& tp);
`construct_from_tuple<T>(tp)` returns `T(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`. Same as `std::make_from_tuple` in {cpp}17.
The name of the function doesn't match the {cpp}17 one to avoid ambiguities when both are visible or in unqualified calls.
## 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` in order 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)`.
## tuple_transform(f, tp...)
template<class F, class... Tp> constexpr /*...*/ tuple_transform(F const& f, Tp&&... tp);
`tuple_transform(f, tp...)` accepts a function object `f` followed by one or more tuples of equal length
(`std::tuple`, `std::pair` and `std::array` are considered tuples.)
The callable `f` must accept as many arguments as there are tuples. The function object is called with the
first elements of each tuple, with the second elements of each tuple, and so on, as if by evaluating
the expression `f(std::get<J>(std::forward<Tp>(tp))...)` for `J` in 0..`N-1`, where `N` is the length of
the tuples.
The order in which the elements of the tuples are processed is unspecified.
The results are returned as a `std::tuple<T...>` with `T...` deduced from the return values of `f` (lvalue
references are preserved, rvalue references are returned by value.)

View File

@@ -0,0 +1,318 @@
////
Copyright 2017-2020 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
////
[#utility]
# Utility Components, <boost/mp11/utility.hpp>
:toc:
:toc-title:
:idprefix:
## mp_identity<T>
template<class T> struct mp_identity
{
using type = T;
};
`mp_identity` is a simple _transformation type trait_ (as per the C++ standard)
that just returns the same type. It's useful both as such, and as a type wrapper
for passing types as values to functions.
.Using mp_identity as a type trait
```
template<class T> using addp_if_not_ref =
typename mp_if<std::is_reference<T>, mp_identity<T>, std::add_pointer<T>>::type;
```
.Using mp_identity to protect qualifiers and references
```
template<class T> void print1()
{
std::cout << typeid(T).name() << std::endl;
}
template<class T> void print2()
{
std::cout << typeid(mp_identity<T>).name() << std::endl;
}
int main()
{
print1<int const&>(); // 'int'
print2<int const&>(); // 'mp_identity<int const &>'
}
```
## mp_identity_t<T>
template<class T> using mp_identity_t = typename mp_identity<T>::type;
## mp_inherit<T...>
template<class... T> struct mp_inherit: T... {};
## mp_if_c<C, T, E...>
template<bool C, class T, class... E> using mp_if_c = /*...*/;
`mp_if_c<true, T, E...>` is an alias for `T`. `mp_if_c<false, T, E>` is an alias for `E`. Otherwise, the result is a substitution failure.
.Using mp_if_c to select between two alternatives
```
using R1 = mp_if_c<true, int, void>; // int
using R2 = mp_if_c<false, int, void>; // void
```
.Using mp_if_c to fail substitution when a condition is not met
```
template<class I> using void_if_5 = mp_if_c<I::value == 5, void>;
```
This example returns `void` when `I::value` is 5, and generates a substitution failure
otherwise. It's the same as `std::enable_if_t<I::value == 5>` in {cpp}14, or
`typename std::enable_if<I::value == 5>::type` in {cpp}11.
## 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.
.Using mp_if to select between two alternatives
```
using R1 = mp_if<mp_true, int, void>; // int
using R2 = mp_if<mp_false, int, void>; // void
```
.Using mp_if to fail substitution when a condition is not met
```
template<class T> using void_if_const = mp_if<std::is_const<T>, void>;
template<class... T> using void_if_all_const =
mp_if<mp_all<std::is_const<T>...>, void>;
template<class T> using if_non_const = mp_if<mp_not<std::is_const<T>>, T>;
```
## 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.
.Using mp_eval_if_c to select the first pack element, or void
```
template<class... T> using first_or_void =
mp_eval_if_c<sizeof...(T) == 0, void, mp_first, mp_list<T...>>;
```
## 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.
.Using mp_eval_if to select the first list element, or void
```
template<class L> using first_or_void = mp_eval_if<mp_empty<L>, void, mp_first, L>;
```
## mp_eval_if_q<C, T, Q, U...>
template<class C, class T, class Q, class... U> using mp_eval_if_q =
mp_eval_if<C, T, Q::template fn, U...>;
Like `mp_eval_if`, but takes a quoted metafunction.
## mp_eval_if_not<C, T, F, U...>
template<class C, class T, template<class...> class F, class... U>
using mp_eval_if_not = mp_eval_if<mp_not<C>, T, F, U...>;
Same as `mp_eval_if`, but the condition is reversed.
## mp_eval_if_not_q<C, T, Q, U...>
template<class C, class T, class Q, class... U> using mp_eval_if_not_q =
mp_eval_if_not<C, T, Q::template fn, U...>;
Same as `mp_eval_if_not`, but takes a quoted metafunction.
## mp_valid<F, T...>
template<template<class...> class F, class... T> using mp_valid = /*...*/;
`mp_valid<F, T...>` is an alias for `mp_true` when `F<T...>` is a valid expression, for `mp_false` otherwise.
.Using mp_valid to write a metafunction that checks for the existence of a nested type
```
template<class T> using get_nested_type = typename T::type;
template<class T> struct has_nested_type: mp_valid<get_nested_type, T> {};
```
## mp_valid_q<Q, T...>
template<class Q, class... T> using mp_valid_q = mp_valid<Q::template fn, T...>;
Like `mp_valid`, but takes a quoted metafunction.
## mp_eval_or<T, F, U...>
template<class T, template<class...> class F, class... U> using mp_eval_or =
mp_eval_if_not<mp_valid<F, U...>, T, F, U...>;
`mp_eval_or<T, F, U...>` is an alias for `F<U...>` when this expression is valid, for `T` otherwise.
.Using mp_eval_or to select the first pack element, or void
```
template<class... T> using first_or_void =
mp_eval_or<void, mp_first, mp_list<T...>>;
```
## mp_eval_or_q<T, Q, U...>
template<class T, class Q, class... U> using mp_eval_or_q =
mp_eval_or<T, Q::template fn, U...>;
Like `mp_eval_or`, but takes a quoted metafunction.
## mp_valid_and_true<F, T...>
template<template<class...> class F, class... T> using mp_valid_and_true =
mp_eval_or<mp_false, F, T...>;
`mp_valid_and_true<F, T...>` is an alias for `F<T...>` when this expression is valid, for `mp_false` otherwise.
## mp_valid_and_true_q<Q, T...>
template<class Q, class... T> using mp_valid_and_true_q =
mp_valid_and_true<Q::template fn, T...>;
Like `mp_valid_and_true`, but takes a quoted metafunction.
## mp_cond<C, T, R...>
template<class C, class T, class... R> using mp_cond = /*...*/;
`mp_cond<C, T, R...>` is an alias for `T` when `static_cast<bool>(C::value)` is `true`.
When `static_cast<bool>(C::value)` is `false`, it's an alias for `mp_cond<R...>`.
(If `static_cast<bool>(C::value)` is a substitution failure, the result is too a substitution
failure.)
.Using mp_cond
```
template<int N> using unsigned_ = mp_cond<
mp_bool<N == 8>, uint8_t,
mp_bool<N == 16>, uint16_t,
mp_bool<N == 32>, uint32_t,
mp_bool<N == 64>, uint64_t,
mp_true, unsigned // default case
>;
```
## mp_defer<F, T...>
template<template<class...> class F, class... T> using mp_defer = /*...*/;
When `mp_valid<F, T...>` is `mp_true`, `mp_defer<F, T...>` is a struct with a nested type `type` which is an alias for `F<T...>`. Otherwise,
`mp_defer<F, T...>` is an empty struct.
## mp_quote<F>
template<template<class...> class F> struct mp_quote
{
template<class... T> using fn = F<T...>;
};
`mp_quote<F>` transforms the template `F` into a _quoted metafunction_, a type with a nested template `fn` such that `fn<T...>` returns `F<T...>`.
.Using mp_quote to make a list of metafunctions
```
using LQ = mp_list<mp_quote<std::is_const>, mp_quote<std::is_volatile>>;
```
## mp_quote_trait<F>
template<template<class...> class F> struct mp_quote_trait
{
template<class... T> using fn = typename F<T...>::type;
};
`mp_quote_trait<F>` transforms the C++03-style trait `F` into a quoted metafunction.
.Using mp_quote_trait with std::add_pointer
```
using L1 = mp_list<int, void, float>;
using R1 = mp_transform_q<mp_quote_trait<std::add_pointer>, L1>;
// mp_list<int*, void*, float*>
```
## mp_invoke_q<Q, T...>
template<class Q, class... T> using mp_invoke_q = typename Q::template fn<T...>;
`mp_invoke_q<Q, T...>` evaluates the nested template `fn` of a quoted metafunction. `mp_invoke_q<mp_quote<F>, T...>` returns `F<T...>`.
.Using mp_invoke_q to invoke a list of metafunctions, technique 1
```
using LQ = mp_list<mp_quote<std::is_const>, mp_quote<std::is_volatile>>;
template<class T> using is_const_and_volatile =
mp_apply<mp_all, mp_product<mp_invoke_q, LQ, mp_list<T>>>;
```
.Using mp_invoke_q to invoke a list of metafunctions, technique 2
```
template<class T> using is_const_and_volatile =
mp_apply<mp_all, mp_transform_q<mp_bind_back<mp_invoke_q, T>, LQ>>;
```
.Using mp_invoke_q to invoke a list of metafunctions, technique 3
```
template<class T> using is_const_and_volatile =
mp_apply<mp_all, mp_transform<mp_invoke_q, LQ, mp_fill<LQ, T>>>;
```
## mp_not_fn<P>
template<template<class...> class P> struct mp_not_fn
{
template<class... T> using fn = mp_not<P<T...>>;
};
`mp_not_fn<P>` returns a quoted metafunction `Q` such that `Q::fn<T...>` returns `mp_not<P<T...>>`.
That is, it negates the result of `P`.
## mp_not_fn_q<Q>
template<class Q> using mp_not_fn_q = mp_not_fn<Q::template fn>;
As `mp_not_fn`, but takes a quoted metafunction.
## mp_compose<F...>
template<template<class...> class... F> struct mp_compose;
`mp_compose<F1, F2, ..., Fn>` is a quoted metafunction that applies
`F1`, `F2`, ..., `Fn` to its argument, in sequence. That is,
`mp_compose<F1, F2, ..., Fn>::fn<T...>` is `Fn<...F2<F1<T...>>...>`.
## mp_compose_q<Q...>
template<class... Q> struct mp_compose_q;
As `mp_compose`, but takes quoted metafunctions.

View File

@@ -0,0 +1,22 @@
#ifndef BOOST_MP11_HPP_INCLUDED
#define BOOST_MP11_HPP_INCLUDED
// Copyright 2015 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
#include <boost/mp11/list.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/mp11/function.hpp>
#include <boost/mp11/map.hpp>
#include <boost/mp11/set.hpp>
#include <boost/mp11/bind.hpp>
#include <boost/mp11/integer_sequence.hpp>
#include <boost/mp11/tuple.hpp>
#endif // #ifndef BOOST_MP11_HPP_INCLUDED

View File

@@ -0,0 +1,111 @@
#ifndef BOOST_MP11_BIND_HPP_INCLUDED
#define BOOST_MP11_BIND_HPP_INCLUDED
// Copyright 2017, 2018 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
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/utility.hpp>
#include <cstddef>
namespace boost
{
namespace mp11
{
// mp_bind_front
template<template<class...> class F, class... T> struct mp_bind_front
{
// the indirection through mp_defer works around the language inability
// to expand U... into a fixed parameter list of an alias template
template<class... U> using fn = typename mp_defer<F, T..., U...>::type;
};
template<class Q, class... T> using mp_bind_front_q = mp_bind_front<Q::template fn, T...>;
// mp_bind_back
template<template<class...> class F, class... T> struct mp_bind_back
{
template<class... U> using fn = typename mp_defer<F, U..., T...>::type;
};
template<class Q, class... T> using mp_bind_back_q = mp_bind_back<Q::template fn, T...>;
// mp_arg
template<std::size_t I> struct mp_arg
{
template<class... T> using fn = mp_at_c<mp_list<T...>, I>;
};
using _1 = mp_arg<0>;
using _2 = mp_arg<1>;
using _3 = mp_arg<2>;
using _4 = mp_arg<3>;
using _5 = mp_arg<4>;
using _6 = mp_arg<5>;
using _7 = mp_arg<6>;
using _8 = mp_arg<7>;
using _9 = mp_arg<8>;
// mp_bind
template<template<class...> class F, class... T> struct mp_bind;
namespace detail
{
template<class V, class... T> struct eval_bound_arg
{
using type = V;
};
template<std::size_t I, class... T> struct eval_bound_arg<mp_arg<I>, T...>
{
using type = typename mp_arg<I>::template fn<T...>;
};
template<template<class...> class F, class... U, class... T> struct eval_bound_arg<mp_bind<F, U...>, T...>
{
using type = typename mp_bind<F, U...>::template fn<T...>;
};
template<template<class...> class F, class... U, class... T> struct eval_bound_arg<mp_bind_front<F, U...>, T...>
{
using type = typename mp_bind_front<F, U...>::template fn<T...>;
};
template<template<class...> class F, class... U, class... T> struct eval_bound_arg<mp_bind_back<F, U...>, T...>
{
using type = typename mp_bind_back<F, U...>::template fn<T...>;
};
} // namespace detail
template<template<class...> class F, class... T> struct mp_bind
{
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, == 1915 )
private:
template<class... U> struct _f { using type = F<typename detail::eval_bound_arg<T, U...>::type...>; };
public:
template<class... U> using fn = typename _f<U...>::type;
#else
template<class... U> using fn = F<typename detail::eval_bound_arg<T, U...>::type...>;
#endif
};
template<class Q, class... T> using mp_bind_q = mp_bind<Q::template fn, T...>;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_BIND_HPP_INCLUDED

View File

@@ -0,0 +1,138 @@
#ifndef BOOST_MP11_DETAIL_CONFIG_HPP_INCLUDED
#define BOOST_MP11_DETAIL_CONFIG_HPP_INCLUDED
// Copyright 2016, 2018, 2019 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_WORKAROUND
#if defined( BOOST_STRICT_CONFIG ) || defined( BOOST_MP11_NO_WORKAROUNDS )
# define BOOST_MP11_WORKAROUND( symbol, test ) 0
#else
# define BOOST_MP11_WORKAROUND( symbol, test ) ((symbol) != 0 && ((symbol) test))
#endif
//
#define BOOST_MP11_CUDA 0
#define BOOST_MP11_CLANG 0
#define BOOST_MP11_INTEL 0
#define BOOST_MP11_GCC 0
#define BOOST_MP11_MSVC 0
#define BOOST_MP11_CONSTEXPR constexpr
#if defined( __CUDACC__ )
// nvcc
# undef BOOST_MP11_CUDA
# define BOOST_MP11_CUDA (__CUDACC_VER_MAJOR__ * 1000000 + __CUDACC_VER_MINOR__ * 10000 + __CUDACC_VER_BUILD__)
// CUDA (8.0) has no constexpr support in msvc mode:
# if defined(_MSC_VER) && (BOOST_MP11_CUDA < 9000000)
# define BOOST_MP11_NO_CONSTEXPR
# undef BOOST_MP11_CONSTEXPR
# define BOOST_MP11_CONSTEXPR
# endif
#endif
#if defined(__clang__)
// Clang
# undef BOOST_MP11_CLANG
# define BOOST_MP11_CLANG (__clang_major__ * 100 + __clang_minor__)
# if defined(__has_cpp_attribute)
# if __has_cpp_attribute(fallthrough) && __cplusplus >= 201406L // Clang 3.9+ in c++1z mode
# define BOOST_MP11_HAS_FOLD_EXPRESSIONS
# endif
# endif
#if BOOST_MP11_CLANG < 400 && __cplusplus >= 201402L \
&& defined( __GLIBCXX__ ) && !__has_include(<shared_mutex>)
// Clang pre-4 in C++14 mode, libstdc++ pre-4.9, ::gets is not defined,
// but Clang tries to import it into std
extern "C" char *gets (char *__s);
#endif
#elif defined(__INTEL_COMPILER)
// Intel C++
# undef BOOST_MP11_INTEL
# define BOOST_MP11_INTEL __INTEL_COMPILER
#elif defined(__GNUC__)
// g++
# undef BOOST_MP11_GCC
# define BOOST_MP11_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#elif defined(_MSC_VER)
// MS Visual C++
# undef BOOST_MP11_MSVC
# define BOOST_MP11_MSVC _MSC_VER
# if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 )
# define BOOST_MP11_NO_CONSTEXPR
# endif
#if _MSC_FULL_VER < 190024210 // 2015u3
# undef BOOST_MP11_CONSTEXPR
# define BOOST_MP11_CONSTEXPR
#endif
#endif
// BOOST_MP11_HAS_CXX14_CONSTEXPR
#if !defined(BOOST_MP11_NO_CONSTEXPR) && defined(__cpp_constexpr) && __cpp_constexpr >= 201304
# define BOOST_MP11_HAS_CXX14_CONSTEXPR
#endif
// BOOST_MP11_HAS_FOLD_EXPRESSIONS
#if !defined(BOOST_MP11_HAS_FOLD_EXPRESSIONS) && defined(__cpp_fold_expressions) && __cpp_fold_expressions >= 201603
# define BOOST_MP11_HAS_FOLD_EXPRESSIONS
#endif
// BOOST_MP11_HAS_TYPE_PACK_ELEMENT
#if defined(__has_builtin)
# if __has_builtin(__type_pack_element)
# define BOOST_MP11_HAS_TYPE_PACK_ELEMENT
# endif
#endif
// BOOST_MP11_DEPRECATED(msg)
#if BOOST_MP11_WORKAROUND( BOOST_MP11_CLANG, < 304 )
# define BOOST_MP11_DEPRECATED(msg)
#elif defined(__GNUC__) || defined(__clang__)
# define BOOST_MP11_DEPRECATED(msg) __attribute__((deprecated(msg)))
#elif defined(_MSC_VER) && _MSC_VER >= 1900
# define BOOST_MP11_DEPRECATED(msg) [[deprecated(msg)]]
#else
# define BOOST_MP11_DEPRECATED(msg)
#endif
#endif // #ifndef BOOST_MP11_DETAIL_CONFIG_HPP_INCLUDED

View File

@@ -0,0 +1,185 @@
#ifndef BOOST_MP11_DETAIL_MP_APPEND_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_APPEND_HPP_INCLUDED
// Copyright 2015-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
#include <boost/mp11/detail/mp_list.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/mp11/detail/config.hpp>
namespace boost
{
namespace mp11
{
// mp_append<L...>
namespace detail
{
template<class... L> struct mp_append_impl;
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 )
template<class... L> struct mp_append_impl
{
};
template<> struct mp_append_impl<>
{
using type = mp_list<>;
};
template<template<class...> class L, class... T> struct mp_append_impl<L<T...>>
{
using type = L<T...>;
};
template<template<class...> class L1, class... T1, template<class...> class L2, class... T2> struct mp_append_impl<L1<T1...>, L2<T2...>>
{
using type = L1<T1..., T2...>;
};
template<template<class...> class L1, class... T1, template<class...> class L2, class... T2, template<class...> class L3, class... T3> struct mp_append_impl<L1<T1...>, L2<T2...>, L3<T3...>>
{
using type = L1<T1..., T2..., T3...>;
};
template<template<class...> class L1, class... T1, template<class...> class L2, class... T2, template<class...> class L3, class... T3, template<class...> class L4, class... T4> struct mp_append_impl<L1<T1...>, L2<T2...>, L3<T3...>, L4<T4...>>
{
using type = L1<T1..., T2..., T3..., T4...>;
};
template<template<class...> class L1, class... T1, template<class...> class L2, class... T2, template<class...> class L3, class... T3, template<class...> class L4, class... T4, template<class...> class L5, class... T5, class... Lr> struct mp_append_impl<L1<T1...>, L2<T2...>, L3<T3...>, L4<T4...>, L5<T5...>, Lr...>
{
using type = typename mp_append_impl<L1<T1..., T2..., T3..., T4..., T5...>, Lr...>::type;
};
#else
template<class L1 = mp_list<>, class L2 = mp_list<>, class L3 = mp_list<>, class L4 = mp_list<>, class L5 = mp_list<>, class L6 = mp_list<>, class L7 = mp_list<>, class L8 = mp_list<>, class L9 = mp_list<>, class L10 = mp_list<>, class L11 = mp_list<>> struct append_11_impl
{
};
template<
template<class...> class L1, class... T1,
template<class...> class L2, class... T2,
template<class...> class L3, class... T3,
template<class...> class L4, class... T4,
template<class...> class L5, class... T5,
template<class...> class L6, class... T6,
template<class...> class L7, class... T7,
template<class...> class L8, class... T8,
template<class...> class L9, class... T9,
template<class...> class L10, class... T10,
template<class...> class L11, class... T11>
struct append_11_impl<L1<T1...>, L2<T2...>, L3<T3...>, L4<T4...>, L5<T5...>, L6<T6...>, L7<T7...>, L8<T8...>, L9<T9...>, L10<T10...>, L11<T11...>>
{
using type = L1<T1..., T2..., T3..., T4..., T5..., T6..., T7..., T8..., T9..., T10..., T11...>;
};
template<
class L00 = mp_list<>, class L01 = mp_list<>, class L02 = mp_list<>, class L03 = mp_list<>, class L04 = mp_list<>, class L05 = mp_list<>, class L06 = mp_list<>, class L07 = mp_list<>, class L08 = mp_list<>, class L09 = mp_list<>, class L0A = mp_list<>,
class L10 = mp_list<>, class L11 = mp_list<>, class L12 = mp_list<>, class L13 = mp_list<>, class L14 = mp_list<>, class L15 = mp_list<>, class L16 = mp_list<>, class L17 = mp_list<>, class L18 = mp_list<>, class L19 = mp_list<>,
class L20 = mp_list<>, class L21 = mp_list<>, class L22 = mp_list<>, class L23 = mp_list<>, class L24 = mp_list<>, class L25 = mp_list<>, class L26 = mp_list<>, class L27 = mp_list<>, class L28 = mp_list<>, class L29 = mp_list<>,
class L30 = mp_list<>, class L31 = mp_list<>, class L32 = mp_list<>, class L33 = mp_list<>, class L34 = mp_list<>, class L35 = mp_list<>, class L36 = mp_list<>, class L37 = mp_list<>, class L38 = mp_list<>, class L39 = mp_list<>,
class L40 = mp_list<>, class L41 = mp_list<>, class L42 = mp_list<>, class L43 = mp_list<>, class L44 = mp_list<>, class L45 = mp_list<>, class L46 = mp_list<>, class L47 = mp_list<>, class L48 = mp_list<>, class L49 = mp_list<>,
class L50 = mp_list<>, class L51 = mp_list<>, class L52 = mp_list<>, class L53 = mp_list<>, class L54 = mp_list<>, class L55 = mp_list<>, class L56 = mp_list<>, class L57 = mp_list<>, class L58 = mp_list<>, class L59 = mp_list<>,
class L60 = mp_list<>, class L61 = mp_list<>, class L62 = mp_list<>, class L63 = mp_list<>, class L64 = mp_list<>, class L65 = mp_list<>, class L66 = mp_list<>, class L67 = mp_list<>, class L68 = mp_list<>, class L69 = mp_list<>,
class L70 = mp_list<>, class L71 = mp_list<>, class L72 = mp_list<>, class L73 = mp_list<>, class L74 = mp_list<>, class L75 = mp_list<>, class L76 = mp_list<>, class L77 = mp_list<>, class L78 = mp_list<>, class L79 = mp_list<>,
class L80 = mp_list<>, class L81 = mp_list<>, class L82 = mp_list<>, class L83 = mp_list<>, class L84 = mp_list<>, class L85 = mp_list<>, class L86 = mp_list<>, class L87 = mp_list<>, class L88 = mp_list<>, class L89 = mp_list<>,
class L90 = mp_list<>, class L91 = mp_list<>, class L92 = mp_list<>, class L93 = mp_list<>, class L94 = mp_list<>, class L95 = mp_list<>, class L96 = mp_list<>, class L97 = mp_list<>, class L98 = mp_list<>, class L99 = mp_list<>,
class LA0 = mp_list<>, class LA1 = mp_list<>, class LA2 = mp_list<>, class LA3 = mp_list<>, class LA4 = mp_list<>, class LA5 = mp_list<>, class LA6 = mp_list<>, class LA7 = mp_list<>, class LA8 = mp_list<>, class LA9 = mp_list<>
> struct append_111_impl
{
using type = typename append_11_impl<
typename append_11_impl<L00, L01, L02, L03, L04, L05, L06, L07, L08, L09, L0A>::type,
typename append_11_impl<mp_list<>, L10, L11, L12, L13, L14, L15, L16, L17, L18, L19>::type,
typename append_11_impl<mp_list<>, L20, L21, L22, L23, L24, L25, L26, L27, L28, L29>::type,
typename append_11_impl<mp_list<>, L30, L31, L32, L33, L34, L35, L36, L37, L38, L39>::type,
typename append_11_impl<mp_list<>, L40, L41, L42, L43, L44, L45, L46, L47, L48, L49>::type,
typename append_11_impl<mp_list<>, L50, L51, L52, L53, L54, L55, L56, L57, L58, L59>::type,
typename append_11_impl<mp_list<>, L60, L61, L62, L63, L64, L65, L66, L67, L68, L69>::type,
typename append_11_impl<mp_list<>, L70, L71, L72, L73, L74, L75, L76, L77, L78, L79>::type,
typename append_11_impl<mp_list<>, L80, L81, L82, L83, L84, L85, L86, L87, L88, L89>::type,
typename append_11_impl<mp_list<>, L90, L91, L92, L93, L94, L95, L96, L97, L98, L99>::type,
typename append_11_impl<mp_list<>, LA0, LA1, LA2, LA3, LA4, LA5, LA6, LA7, LA8, LA9>::type
>::type;
};
template<
class L00, class L01, class L02, class L03, class L04, class L05, class L06, class L07, class L08, class L09, class L0A,
class L10, class L11, class L12, class L13, class L14, class L15, class L16, class L17, class L18, class L19,
class L20, class L21, class L22, class L23, class L24, class L25, class L26, class L27, class L28, class L29,
class L30, class L31, class L32, class L33, class L34, class L35, class L36, class L37, class L38, class L39,
class L40, class L41, class L42, class L43, class L44, class L45, class L46, class L47, class L48, class L49,
class L50, class L51, class L52, class L53, class L54, class L55, class L56, class L57, class L58, class L59,
class L60, class L61, class L62, class L63, class L64, class L65, class L66, class L67, class L68, class L69,
class L70, class L71, class L72, class L73, class L74, class L75, class L76, class L77, class L78, class L79,
class L80, class L81, class L82, class L83, class L84, class L85, class L86, class L87, class L88, class L89,
class L90, class L91, class L92, class L93, class L94, class L95, class L96, class L97, class L98, class L99,
class LA0, class LA1, class LA2, class LA3, class LA4, class LA5, class LA6, class LA7, class LA8, class LA9,
class... Lr
> struct append_inf_impl
{
using prefix = typename append_111_impl<
L00, L01, L02, L03, L04, L05, L06, L07, L08, L09, L0A,
L10, L11, L12, L13, L14, L15, L16, L17, L18, L19,
L20, L21, L22, L23, L24, L25, L26, L27, L28, L29,
L30, L31, L32, L33, L34, L35, L36, L37, L38, L39,
L40, L41, L42, L43, L44, L45, L46, L47, L48, L49,
L50, L51, L52, L53, L54, L55, L56, L57, L58, L59,
L60, L61, L62, L63, L64, L65, L66, L67, L68, L69,
L70, L71, L72, L73, L74, L75, L76, L77, L78, L79,
L80, L81, L82, L83, L84, L85, L86, L87, L88, L89,
L90, L91, L92, L93, L94, L95, L96, L97, L98, L99,
LA0, LA1, LA2, LA3, LA4, LA5, LA6, LA7, LA8, LA9
>::type;
using type = typename mp_append_impl<prefix, Lr...>::type;
};
#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 )
template<class... L>
struct mp_append_impl_cuda_workaround
{
using type = mp_if_c<(sizeof...(L) > 111), mp_quote<append_inf_impl>, mp_if_c<(sizeof...(L) > 11), mp_quote<append_111_impl>, mp_quote<append_11_impl> > >;
};
template<class... L> struct mp_append_impl: mp_append_impl_cuda_workaround<L...>::type::template fn<L...>
{
};
#else
template<class... L> struct mp_append_impl: mp_if_c<(sizeof...(L) > 111), mp_quote<append_inf_impl>, mp_if_c<(sizeof...(L) > 11), mp_quote<append_111_impl>, mp_quote<append_11_impl> > >::template fn<L...>
{
};
#endif
#endif
} // namespace detail
template<class... L> using mp_append = typename detail::mp_append_impl<L...>::type;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_APPEND_HPP_INCLUDED

View File

@@ -0,0 +1,48 @@
#ifndef BOOST_MP11_DETAIL_MP_COPY_IF_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_COPY_IF_HPP_INCLUDED
// Copyright 2015-2019 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
#include <boost/mp11/utility.hpp>
#include <boost/mp11/detail/mp_list.hpp>
#include <boost/mp11/detail/mp_append.hpp>
#include <boost/mp11/detail/config.hpp>
namespace boost
{
namespace mp11
{
// mp_copy_if<L, P>
namespace detail
{
template<class L, template<class...> class P> struct mp_copy_if_impl
{
};
template<template<class...> class L, class... T, template<class...> class P> struct mp_copy_if_impl<L<T...>, P>
{
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 )
template<class U> struct _f { using type = mp_if<P<U>, mp_list<U>, mp_list<>>; };
using type = mp_append<L<>, typename _f<T>::type...>;
#else
template<class U> using _f = mp_if<P<U>, mp_list<U>, mp_list<>>;
using type = mp_append<L<>, _f<T>...>;
#endif
};
} // namespace detail
template<class L, template<class...> class P> using mp_copy_if = typename detail::mp_copy_if_impl<L, P>::type;
template<class L, class Q> using mp_copy_if_q = mp_copy_if<L, Q::template fn>;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_COPY_IF_HPP_INCLUDED

View File

@@ -0,0 +1,147 @@
#ifndef BOOST_MP11_DETAIL_MP_COUNT_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_COUNT_HPP_INCLUDED
// Copyright 2015, 2016 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
#include <boost/mp11/integral.hpp>
#include <boost/mp11/detail/mp_plus.hpp>
#include <boost/mp11/detail/config.hpp>
namespace boost
{
namespace mp11
{
// mp_count<L, V>
namespace detail
{
#if !defined( BOOST_MP11_NO_CONSTEXPR )
constexpr std::size_t cx_plus()
{
return 0;
}
template<class T1, class... T> constexpr std::size_t cx_plus(T1 t1, T... t)
{
return static_cast<std::size_t>(t1) + cx_plus(t...);
}
template<class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class... T>
constexpr std::size_t cx_plus(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T... t)
{
return static_cast<std::size_t>(t1 + t2 + t3 + t4 + t5 + t6 + t7 + t8 + t9 + t10) + cx_plus(t...);
}
#endif
template<class L, class V> struct mp_count_impl;
#if defined( BOOST_MP11_HAS_CXX14_CONSTEXPR )
template<class V, class... T> constexpr std::size_t cx_count()
{
constexpr bool a[] = { false, std::is_same<T, V>::value... };
std::size_t r = 0;
for( std::size_t i = 1; i < sizeof...(T) + 1; ++i )
{
r += a[ i ];
}
return r;
}
template<template<class...> class L, class... T, class V> struct mp_count_impl<L<T...>, V>
{
using type = mp_size_t<cx_count<V, T...>()>;
};
#elif !defined( BOOST_MP11_NO_CONSTEXPR )
template<template<class...> class L, class... T, class V> struct mp_count_impl<L<T...>, V>
{
using type = mp_size_t<cx_plus(std::is_same<T, V>::value...)>;
};
#else
template<template<class...> class L, class... T, class V> struct mp_count_impl<L<T...>, V>
{
using type = mp_size_t<mp_plus<std::is_same<T, V>...>::value>;
};
#endif
} // namespace detail
template<class L, class V> using mp_count = typename detail::mp_count_impl<L, V>::type;
// mp_count_if<L, P>
namespace detail
{
template<class L, template<class...> class P> struct mp_count_if_impl;
#if defined( BOOST_MP11_HAS_CXX14_CONSTEXPR ) && !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1930 )
template<template<class...> class P, class... T> constexpr std::size_t cx_count_if()
{
constexpr bool a[] = { false, static_cast<bool>( P<T>::value )... };
std::size_t r = 0;
for( std::size_t i = 1; i < sizeof...(T) + 1; ++i )
{
r += a[ i ];
}
return r;
}
template<template<class...> class L, class... T, template<class...> class P> struct mp_count_if_impl<L<T...>, P>
{
using type = mp_size_t<cx_count_if<P, T...>()>;
};
#elif !defined( BOOST_MP11_NO_CONSTEXPR )
template<template<class...> class L, class... T, template<class...> class P> struct mp_count_if_impl<L<T...>, P>
{
using type = mp_size_t<cx_plus(mp_to_bool<P<T>>::value...)>;
};
#else
template<template<class...> class L, class... T, template<class...> class P> struct mp_count_if_impl<L<T...>, P>
{
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 )
template<class T> struct _f { using type = mp_to_bool<P<T>>; };
using type = mp_size_t<mp_plus<typename _f<T>::type...>::value>;
#else
using type = mp_size_t<mp_plus<mp_to_bool<P<T>>...>::value>;
#endif
};
#endif
} // namespace detail
template<class L, template<class...> class P> using mp_count_if = typename detail::mp_count_if_impl<L, P>::type;
template<class L, class Q> using mp_count_if_q = mp_count_if<L, Q::template fn>;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_COUNT_HPP_INCLUDED

View File

@@ -0,0 +1,62 @@
#ifndef BOOST_MP11_DETAIL_MP_FOLD_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_FOLD_HPP_INCLUDED
// Copyright 2015-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
#include <boost/mp11/detail/config.hpp>
namespace boost
{
namespace mp11
{
// mp_fold<L, V, F>
namespace detail
{
template<class L, class V, template<class...> class F> struct mp_fold_impl
{
// An error "no type named 'type'" here means that the first argument to mp_fold is not a list
};
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 )
template<template<class...> class L, class... T, class V, template<class...> class F> struct mp_fold_impl<L<T...>, V, F>
{
static_assert( sizeof...(T) == 0, "T... must be empty" );
using type = V;
};
#else
template<template<class...> class L, class V, template<class...> class F> struct mp_fold_impl<L<>, V, F>
{
using type = V;
};
#endif
template<template<class...> class L, class T1, class... T, class V, template<class...> class F> struct mp_fold_impl<L<T1, T...>, V, F>
{
using type = typename mp_fold_impl<L<T...>, F<V, T1>, F>::type;
};
template<template<class...> class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class... T, class V, template<class...> class F> struct mp_fold_impl<L<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T...>, V, F>
{
using type = typename mp_fold_impl<L<T...>, F<F<F<F<F<F<F<F<F<F<V, T1>, T2>, T3>, T4>, T5>, T6>, T7>, T8>, T9>, T10>, F>::type;
};
} // namespace detail
template<class L, class V, template<class...> class F> using mp_fold = typename detail::mp_fold_impl<L, V, F>::type;
template<class L, class V, class Q> using mp_fold_q = mp_fold<L, V, Q::template fn>;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_FOLD_HPP_INCLUDED

View File

@@ -0,0 +1,38 @@
#ifndef BOOST_MP11_DETAIL_MP_FRONT_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_FRONT_HPP_INCLUDED
// Copyright 2015-2021 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
namespace boost
{
namespace mp11
{
// mp_front<L>
namespace detail
{
template<class L> struct mp_front_impl
{
// An error "no type named 'type'" here means that the argument to mp_front
// is either not a list, or is an empty list
};
template<template<class...> class L, class T1, class... T> struct mp_front_impl<L<T1, T...>>
{
using type = T1;
};
} // namespace detail
template<class L> using mp_front = typename detail::mp_front_impl<L>::type;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_FRONT_HPP_INCLUDED

View File

@@ -0,0 +1,39 @@
#ifndef BOOST_MP11_DETAIL_MP_IS_LIST_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_IS_LIST_HPP_INCLUDED
// Copyright 2015-2019 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
#include <boost/mp11/integral.hpp>
namespace boost
{
namespace mp11
{
// mp_is_list<L>
namespace detail
{
template<class L> struct mp_is_list_impl
{
using type = mp_false;
};
template<template<class...> class L, class... T> struct mp_is_list_impl<L<T...>>
{
using type = mp_true;
};
} // namespace detail
template<class L> using mp_is_list = typename detail::mp_is_list_impl<L>::type;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_IS_LIST_HPP_INCLUDED

View File

@@ -0,0 +1,24 @@
#ifndef BOOST_MP11_DETAIL_MP_LIST_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_LIST_HPP_INCLUDED
// Copyright 2015, 2016 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
namespace boost
{
namespace mp11
{
// mp_list<T...>
template<class... T> struct mp_list
{
};
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_LIST_HPP_INCLUDED

View File

@@ -0,0 +1,87 @@
#ifndef BOOST_MP11_DETAIL_MP_MAP_FIND_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_MAP_FIND_HPP_INCLUDED
// Copyright 2015 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
#include <boost/mp11/utility.hpp>
#include <boost/mp11/detail/config.hpp>
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1930 )
// not exactly good practice, but...
namespace std
{
template<class... _Types> class tuple;
}
#endif
namespace boost
{
namespace mp11
{
// mp_map_find
namespace detail
{
#if !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1930 )
template<class T> using mpmf_wrap = mp_identity<T>;
template<class T> using mpmf_unwrap = typename T::type;
#else
template<class... T> struct mpmf_tuple {};
template<class T> struct mpmf_wrap_impl
{
using type = mp_identity<T>;
};
template<class... T> struct mpmf_wrap_impl< std::tuple<T...> >
{
using type = mp_identity< mpmf_tuple<T...> >;
};
template<class T> using mpmf_wrap = typename mpmf_wrap_impl<T>::type;
template<class T> struct mpmf_unwrap_impl
{
using type = typename T::type;
};
template<class... T> struct mpmf_unwrap_impl< mp_identity< mpmf_tuple<T...> > >
{
using type = std::tuple<T...>;
};
template<class T> using mpmf_unwrap = typename mpmf_unwrap_impl<T>::type;
#endif // #if !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1930 )
template<class M, class K> struct mp_map_find_impl;
template<template<class...> class M, class... T, class K> struct mp_map_find_impl<M<T...>, K>
{
using U = mp_inherit<mpmf_wrap<T>...>;
template<template<class...> class L, class... U> static mp_identity<L<K, U...>> f( mp_identity<L<K, U...>>* );
static mp_identity<void> f( ... );
using type = mpmf_unwrap< decltype( f((U*)0) ) >;
};
} // namespace detail
template<class M, class K> using mp_map_find = typename detail::mp_map_find_impl<M, K>::type;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_MAP_FIND_HPP_INCLUDED

View File

@@ -0,0 +1,51 @@
#ifndef BOOST_MP11_DETAIL_MP_MIN_ELEMENT_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_MIN_ELEMENT_HPP_INCLUDED
// Copyright 2015-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
#include <boost/mp11/detail/mp_fold.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/utility.hpp>
namespace boost
{
namespace mp11
{
// mp_min_element<L, P>
namespace detail
{
template<template<class...> class P> struct select_min
{
template<class T1, class T2> using fn = mp_if<P<T1, T2>, T1, T2>;
};
} // namespace detail
template<class L, template<class...> class P> using mp_min_element = mp_fold_q<mp_rest<L>, mp_first<L>, detail::select_min<P>>;
template<class L, class Q> using mp_min_element_q = mp_min_element<L, Q::template fn>;
// mp_max_element<L, P>
namespace detail
{
template<template<class...> class P> struct select_max
{
template<class T1, class T2> using fn = mp_if<P<T2, T1>, T1, T2>;
};
} // namespace detail
template<class L, template<class...> class P> using mp_max_element = mp_fold_q<mp_rest<L>, mp_first<L>, detail::select_max<P>>;
template<class L, class Q> using mp_max_element_q = mp_max_element<L, Q::template fn>;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_MIN_ELEMENT_HPP_INCLUDED

View File

@@ -0,0 +1,81 @@
#ifndef BOOST_MP11_DETAIL_MP_PLUS_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_PLUS_HPP_INCLUDED
// Copyright 2015 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
#include <boost/mp11/detail/config.hpp>
#include <type_traits>
namespace boost
{
namespace mp11
{
// mp_plus
namespace detail
{
#if defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) && !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 )
template<class... T> struct mp_plus_impl
{
static const auto _v = (T::value + ... + 0);
using type = std::integral_constant<typename std::remove_const<decltype(_v)>::type, _v>;
};
#else
template<class... T> struct mp_plus_impl;
template<> struct mp_plus_impl<>
{
using type = std::integral_constant<int, 0>;
};
#if BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 40800 )
template<class T1, class... T> struct mp_plus_impl<T1, T...>
{
static const decltype(T1::value + mp_plus_impl<T...>::type::value) _v = T1::value + mp_plus_impl<T...>::type::value;
using type = std::integral_constant<typename std::remove_const<decltype(_v)>::type, _v>;
};
template<class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class... T> struct mp_plus_impl<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T...>
{
static const
decltype(T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl<T...>::type::value)
_v = T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl<T...>::type::value;
using type = std::integral_constant<typename std::remove_const<decltype(_v)>::type, _v>;
};
#else
template<class T1, class... T> struct mp_plus_impl<T1, T...>
{
static const auto _v = T1::value + mp_plus_impl<T...>::type::value;
using type = std::integral_constant<typename std::remove_const<decltype(_v)>::type, _v>;
};
template<class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class... T> struct mp_plus_impl<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T...>
{
static const auto _v = T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl<T...>::type::value;
using type = std::integral_constant<typename std::remove_const<decltype(_v)>::type, _v>;
};
#endif
#endif
} // namespace detail
template<class... T> using mp_plus = typename detail::mp_plus_impl<T...>::type;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_PLUS_HPP_INCLUDED

View File

@@ -0,0 +1,48 @@
#ifndef BOOST_MP11_DETAIL_MP_REMOVE_IF_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_REMOVE_IF_HPP_INCLUDED
// Copyright 2015-2019 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
#include <boost/mp11/utility.hpp>
#include <boost/mp11/detail/mp_list.hpp>
#include <boost/mp11/detail/mp_append.hpp>
#include <boost/mp11/detail/config.hpp>
namespace boost
{
namespace mp11
{
// mp_remove_if<L, P>
namespace detail
{
template<class L, template<class...> class P> struct mp_remove_if_impl
{
};
template<template<class...> class L, class... T, template<class...> class P> struct mp_remove_if_impl<L<T...>, P>
{
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 )
template<class U> struct _f { using type = mp_if<P<U>, mp_list<>, mp_list<U>>; };
using type = mp_append<L<>, typename _f<T>::type...>;
#else
template<class U> using _f = mp_if<P<U>, mp_list<>, mp_list<U>>;
using type = mp_append<L<>, _f<T>...>;
#endif
};
} // namespace detail
template<class L, template<class...> class P> using mp_remove_if = typename detail::mp_remove_if_impl<L, P>::type;
template<class L, class Q> using mp_remove_if_q = mp_remove_if<L, Q::template fn>;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_REMOVE_IF_HPP_INCLUDED

View File

@@ -0,0 +1,41 @@
#ifndef BOOST_MP11_DETAIL_MP_RENAME_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_RENAME_HPP_INCLUDED
// Copyright 2015-2021 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
namespace boost
{
namespace mp11
{
// mp_rename<L, B>
namespace detail
{
template<class A, template<class...> class B> struct mp_rename_impl
{
// An error "no type named 'type'" here means that the first argument to mp_rename is not a list
};
template<template<class...> class A, class... T, template<class...> class B> struct mp_rename_impl<A<T...>, B>
{
using type = B<T...>;
};
} // namespace detail
template<class A, template<class...> class B> using mp_rename = typename detail::mp_rename_impl<A, B>::type;
template<template<class...> class F, class L> using mp_apply = typename detail::mp_rename_impl<L, F>::type;
template<class Q, class L> using mp_apply_q = typename detail::mp_rename_impl<L, Q::template fn>::type;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_RENAME_HPP_INCLUDED

View File

@@ -0,0 +1,32 @@
#ifndef BOOST_MP11_DETAIL_MP_VOID_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_VOID_HPP_INCLUDED
// Copyright 2015-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
namespace boost
{
namespace mp11
{
// mp_void<T...>
namespace detail
{
template<class... T> struct mp_void_impl
{
using type = void;
};
} // namespace detail
template<class... T> using mp_void = typename detail::mp_void_impl<T...>::type;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_VOID_HPP_INCLUDED

View File

@@ -0,0 +1,385 @@
#ifndef BOOST_MP11_DETAIL_MP_WITH_INDEX_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MP_WITH_INDEX_HPP_INCLUDED
// 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
#include <boost/mp11/integral.hpp>
#include <boost/mp11/detail/config.hpp>
#include <type_traits>
#include <utility>
#include <cassert>
#if defined( BOOST_MP11_HAS_CXX14_CONSTEXPR )
# define BOOST_MP11_CONSTEXPR14 constexpr
#else
# define BOOST_MP11_CONSTEXPR14
#endif
#if defined( __GNUC__ ) || defined( __clang__ )
# define BOOST_MP11_UNREACHABLE_DEFAULT default: __builtin_unreachable();
#elif defined( _MSC_VER )
# define BOOST_MP11_UNREACHABLE_DEFAULT default: __assume(false);
#else
# define BOOST_MP11_UNREACHABLE_DEFAULT
#endif
namespace boost
{
namespace mp11
{
namespace detail
{
template<std::size_t N> struct mp_with_index_impl_
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
if( i < N / 2 )
{
return mp_with_index_impl_<N/2>::template call<K>( i, std::forward<F>(f) );
}
else
{
return mp_with_index_impl_<N-N/2>::template call<K+N/2>( i - N/2, std::forward<F>(f) );
}
}
};
template<> struct mp_with_index_impl_<0>
{
};
template<> struct mp_with_index_impl_<1>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t /*i*/, F && f )
{
return std::forward<F>(f)( mp_size_t<K+0>() );
}
};
template<> struct mp_with_index_impl_<2>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
}
}
};
template<> struct mp_with_index_impl_<3>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
}
}
};
template<> struct mp_with_index_impl_<4>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
}
}
};
template<> struct mp_with_index_impl_<5>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
}
}
};
template<> struct mp_with_index_impl_<6>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
}
}
};
template<> struct mp_with_index_impl_<7>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
}
}
};
template<> struct mp_with_index_impl_<8>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
}
}
};
template<> struct mp_with_index_impl_<9>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
}
}
};
template<> struct mp_with_index_impl_<10>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
}
}
};
template<> struct mp_with_index_impl_<11>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
}
}
};
template<> struct mp_with_index_impl_<12>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
}
}
};
template<> struct mp_with_index_impl_<13>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
}
}
};
template<> struct mp_with_index_impl_<14>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
case 13: return std::forward<F>(f)( mp_size_t<K+13>() );
}
}
};
template<> struct mp_with_index_impl_<15>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
case 13: return std::forward<F>(f)( mp_size_t<K+13>() );
case 14: return std::forward<F>(f)( mp_size_t<K+14>() );
}
}
};
template<> struct mp_with_index_impl_<16>
{
template<std::size_t K, class F> static BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) call( std::size_t i, F && f )
{
switch( i )
{
BOOST_MP11_UNREACHABLE_DEFAULT
case 0: return std::forward<F>(f)( mp_size_t<K+0>() );
case 1: return std::forward<F>(f)( mp_size_t<K+1>() );
case 2: return std::forward<F>(f)( mp_size_t<K+2>() );
case 3: return std::forward<F>(f)( mp_size_t<K+3>() );
case 4: return std::forward<F>(f)( mp_size_t<K+4>() );
case 5: return std::forward<F>(f)( mp_size_t<K+5>() );
case 6: return std::forward<F>(f)( mp_size_t<K+6>() );
case 7: return std::forward<F>(f)( mp_size_t<K+7>() );
case 8: return std::forward<F>(f)( mp_size_t<K+8>() );
case 9: return std::forward<F>(f)( mp_size_t<K+9>() );
case 10: return std::forward<F>(f)( mp_size_t<K+10>() );
case 11: return std::forward<F>(f)( mp_size_t<K+11>() );
case 12: return std::forward<F>(f)( mp_size_t<K+12>() );
case 13: return std::forward<F>(f)( mp_size_t<K+13>() );
case 14: return std::forward<F>(f)( mp_size_t<K+14>() );
case 15: return std::forward<F>(f)( mp_size_t<K+15>() );
}
}
};
} // namespace detail
template<std::size_t N, class F> inline BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) mp_with_index( std::size_t i, F && f )
{
assert( i < N );
return detail::mp_with_index_impl_<N>::template call<0>( i, std::forward<F>(f) );
}
template<class N, class F> inline BOOST_MP11_CONSTEXPR14 decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) mp_with_index( std::size_t i, F && f )
{
return mp_with_index<std::size_t{N::value}>( i, std::forward<F>(f) );
}
#undef BOOST_MP11_CONSTEXPR14
#undef BOOST_MP11_UNREACHABLE_DEFAULT
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MP_WITH_INDEX_HPP_INCLUDED

View File

@@ -0,0 +1,160 @@
#ifndef BOOST_MP11_DETAIL_MPL_COMMON_HPP_INCLUDED
#define BOOST_MP11_DETAIL_MPL_COMMON_HPP_INCLUDED
// Copyright 2017, 2019 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
#include <boost/mp11/list.hpp>
#include <boost/mp11/algorithm.hpp>
namespace boost
{
namespace mpl
{
struct forward_iterator_tag;
namespace aux
{
struct mp11_tag {};
template<class L> struct mp11_iterator
{
using category = forward_iterator_tag;
using type = mp11::mp_first<L>;
using next = mp11_iterator<mp11::mp_rest<L>>;
};
} // namespace aux
// at
template< typename Tag > struct at_impl;
template<> struct at_impl<aux::mp11_tag>
{
template<class L, class I> struct apply
{
using type = mp11::mp_at<L, I>;
};
};
// back
template< typename Tag > struct back_impl;
template<> struct back_impl<aux::mp11_tag>
{
template<class L> struct apply
{
using N = mp11::mp_size<L>;
using type = mp11::mp_at_c<L, N::value - 1>;
};
};
// begin
template< typename Tag > struct begin_impl;
template<> struct begin_impl<aux::mp11_tag>
{
template<class L> struct apply
{
using type = aux::mp11_iterator<L>;
};
};
// clear
template< typename Tag > struct clear_impl;
template<> struct clear_impl<aux::mp11_tag>
{
template<class L> struct apply
{
using type = mp11::mp_clear<L>;
};
};
// end
template< typename Tag > struct end_impl;
template<> struct end_impl<aux::mp11_tag>
{
template<class L> struct apply
{
using type = aux::mp11_iterator<mp11::mp_clear<L>>;
};
};
// front
template< typename Tag > struct front_impl;
template<> struct front_impl<aux::mp11_tag>
{
template<class L> struct apply
{
using type = mp11::mp_front<L>;
};
};
// pop_front
template< typename Tag > struct pop_front_impl;
template<> struct pop_front_impl<aux::mp11_tag>
{
template<class L> struct apply
{
using type = mp11::mp_pop_front<L>;
};
};
// push_back
template< typename Tag > struct push_back_impl;
template<> struct push_back_impl<aux::mp11_tag>
{
template<class L, class T> struct apply
{
using type = mp11::mp_push_back<L, T>;
};
};
// push_front
template< typename Tag > struct push_front_impl;
template<> struct push_front_impl<aux::mp11_tag>
{
template<class L, class T> struct apply
{
using type = mp11::mp_push_front<L, T>;
};
};
// size
template< typename Tag > struct size_impl;
template<> struct size_impl<aux::mp11_tag>
{
template<class L> struct apply
{
using type = mp11::mp_size<L>;
};
};
} // namespace mpl
} // namespace boost
#endif // #ifndef BOOST_MP11_DETAIL_MPL_COMMON_HPP_INCLUDED

View File

@@ -0,0 +1,222 @@
#ifndef BOOST_MP11_FUNCTION_HPP_INCLUDED
#define BOOST_MP11_FUNCTION_HPP_INCLUDED
// Copyright 2015-2019 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
#include <boost/mp11/integral.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/mp11/detail/mp_list.hpp>
#include <boost/mp11/detail/mp_count.hpp>
#include <boost/mp11/detail/mp_plus.hpp>
#include <boost/mp11/detail/mp_min_element.hpp>
#include <boost/mp11/detail/mp_void.hpp>
#include <boost/mp11/detail/config.hpp>
#include <type_traits>
namespace boost
{
namespace mp11
{
// mp_void<T...>
// in detail/mp_void.hpp
// mp_and<T...>
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1910 )
namespace detail
{
template<class... T> struct mp_and_impl;
} // namespace detail
template<class... T> using mp_and = mp_to_bool< typename detail::mp_and_impl<T...>::type >;
namespace detail
{
template<> struct mp_and_impl<>
{
using type = mp_true;
};
template<class T> struct mp_and_impl<T>
{
using type = T;
};
template<class T1, class... T> struct mp_and_impl<T1, T...>
{
using type = mp_eval_if< mp_not<T1>, T1, mp_and, T... >;
};
} // namespace detail
#else
namespace detail
{
template<class L, class E = void> struct mp_and_impl
{
using type = mp_false;
};
template<class... T> struct mp_and_impl< mp_list<T...>, mp_void<mp_if<T, void>...> >
{
using type = mp_true;
};
} // namespace detail
template<class... T> using mp_and = typename detail::mp_and_impl<mp_list<T...>>::type;
#endif
// mp_all<T...>
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86355
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) || BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, != 0 )
template<class... T> using mp_all = mp_bool< mp_count_if< mp_list<T...>, mp_not >::value == 0 >;
#else
template<class... T> using mp_all = mp_bool< mp_count< mp_list<mp_to_bool<T>...>, mp_false >::value == 0 >;
#endif
// mp_or<T...>
namespace detail
{
template<class... T> struct mp_or_impl;
} // namespace detail
template<class... T> using mp_or = mp_to_bool< typename detail::mp_or_impl<T...>::type >;
namespace detail
{
template<> struct mp_or_impl<>
{
using type = mp_false;
};
template<class T> struct mp_or_impl<T>
{
using type = T;
};
template<class T1, class... T> struct mp_or_impl<T1, T...>
{
using type = mp_eval_if< T1, T1, mp_or, T... >;
};
} // namespace detail
// mp_any<T...>
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86356
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) || BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, != 0 )
template<class... T> using mp_any = mp_bool< mp_count_if< mp_list<T...>, mp_to_bool >::value != 0 >;
#else
template<class... T> using mp_any = mp_bool< mp_count< mp_list<mp_to_bool<T>...>, mp_true >::value != 0 >;
#endif
// mp_same<T...>
namespace detail
{
template<class... T> struct mp_same_impl;
template<> struct mp_same_impl<>
{
using type = mp_true;
};
template<class T1, class... T> struct mp_same_impl<T1, T...>
{
using type = mp_bool< mp_count<mp_list<T...>, T1>::value == sizeof...(T) >;
};
} // namespace detail
template<class... T> using mp_same = typename detail::mp_same_impl<T...>::type;
// mp_similar<T...>
namespace detail
{
template<class... T> struct mp_similar_impl;
template<> struct mp_similar_impl<>
{
using type = mp_true;
};
template<class T> struct mp_similar_impl<T>
{
using type = mp_true;
};
template<class T> struct mp_similar_impl<T, T>
{
using type = mp_true;
};
template<class T1, class T2> struct mp_similar_impl<T1, T2>
{
using type = mp_false;
};
template<template<class...> class L, class... T1, class... T2> struct mp_similar_impl<L<T1...>, L<T2...>>
{
using type = mp_true;
};
template<template<class...> class L, class... T> struct mp_similar_impl<L<T...>, L<T...>>
{
using type = mp_true;
};
template<class T1, class T2, class T3, class... T> struct mp_similar_impl<T1, T2, T3, T...>
{
using type = mp_all< typename mp_similar_impl<T1, T2>::type, typename mp_similar_impl<T1, T3>::type, typename mp_similar_impl<T1, T>::type... >;
};
} // namespace detail
template<class... T> using mp_similar = typename detail::mp_similar_impl<T...>::type;
#if BOOST_MP11_GCC
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-compare"
#endif
// mp_less<T1, T2>
template<class T1, class T2> using mp_less = mp_bool<(T1::value < 0 && T2::value >= 0) || ((T1::value < T2::value) && !(T1::value >= 0 && T2::value < 0))>;
#if BOOST_MP11_GCC
# pragma GCC diagnostic pop
#endif
// mp_min<T...>
template<class T1, class... T> using mp_min = mp_min_element<mp_list<T1, T...>, mp_less>;
// mp_max<T...>
template<class T1, class... T> using mp_max = mp_max_element<mp_list<T1, T...>, mp_less>;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_FUNCTION_HPP_INCLUDED

View File

@@ -0,0 +1,112 @@
#ifndef BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED
#define BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED
// Copyright 2015, 2017, 2019 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
#include <boost/mp11/version.hpp>
#include <cstddef>
#if defined(__has_builtin)
# if __has_builtin(__make_integer_seq)
# define BOOST_MP11_HAS_MAKE_INTEGER_SEQ
# endif
#endif
namespace boost
{
namespace mp11
{
// integer_sequence
template<class T, T... I> struct integer_sequence
{
};
#if defined(BOOST_MP11_HAS_MAKE_INTEGER_SEQ)
template<class T, T N> using make_integer_sequence = __make_integer_seq<integer_sequence, T, N>;
#else
// detail::make_integer_sequence_impl
namespace detail
{
// iseq_if_c
template<bool C, class T, class E> struct iseq_if_c_impl;
template<class T, class E> struct iseq_if_c_impl<true, T, E>
{
using type = T;
};
template<class T, class E> struct iseq_if_c_impl<false, T, E>
{
using type = E;
};
template<bool C, class T, class E> using iseq_if_c = typename iseq_if_c_impl<C, T, E>::type;
// iseq_identity
template<class T> struct iseq_identity
{
using type = T;
};
template<class S1, class S2> struct append_integer_sequence;
template<class T, T... I, T... J> struct append_integer_sequence<integer_sequence<T, I...>, integer_sequence<T, J...>>
{
using type = integer_sequence< T, I..., ( J + sizeof...(I) )... >;
};
template<class T, T N> struct make_integer_sequence_impl;
template<class T, T N> struct make_integer_sequence_impl_
{
private:
static_assert( N >= 0, "make_integer_sequence<T, N>: N must not be negative" );
static T const M = N / 2;
static T const R = N % 2;
using S1 = typename make_integer_sequence_impl<T, M>::type;
using S2 = typename append_integer_sequence<S1, S1>::type;
using S3 = typename make_integer_sequence_impl<T, R>::type;
using S4 = typename append_integer_sequence<S2, S3>::type;
public:
using type = S4;
};
template<class T, T N> struct make_integer_sequence_impl: iseq_if_c<N == 0, iseq_identity<integer_sequence<T>>, iseq_if_c<N == 1, iseq_identity<integer_sequence<T, 0>>, make_integer_sequence_impl_<T, N> > >
{
};
} // namespace detail
// make_integer_sequence
template<class T, T N> using make_integer_sequence = typename detail::make_integer_sequence_impl<T, N>::type;
#endif // defined(BOOST_MP11_HAS_MAKE_INTEGER_SEQ)
// index_sequence
template<std::size_t... I> using index_sequence = integer_sequence<std::size_t, I...>;
// make_index_sequence
template<std::size_t N> using make_index_sequence = make_integer_sequence<std::size_t, N>;
// index_sequence_for
template<class... T> using index_sequence_for = make_integer_sequence<std::size_t, sizeof...(T)>;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED

View File

@@ -0,0 +1,41 @@
#ifndef BOOST_MP11_INTEGRAL_HPP_INCLUDED
#define BOOST_MP11_INTEGRAL_HPP_INCLUDED
// Copyright 2015 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
#include <boost/mp11/version.hpp>
#include <type_traits>
#include <cstddef>
namespace boost
{
namespace mp11
{
// mp_bool
template<bool B> using mp_bool = std::integral_constant<bool, B>;
using mp_true = mp_bool<true>;
using mp_false = mp_bool<false>;
// mp_to_bool
template<class T> using mp_to_bool = mp_bool<static_cast<bool>( T::value )>;
// mp_not<T>
template<class T> using mp_not = mp_bool< !T::value >;
// mp_int
template<int I> using mp_int = std::integral_constant<int, I>;
// mp_size_t
template<std::size_t N> using mp_size_t = std::integral_constant<std::size_t, N>;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_INTEGRAL_HPP_INCLUDED

View File

@@ -0,0 +1,304 @@
#ifndef BOOST_MP11_LIST_HPP_INCLUDED
#define BOOST_MP11_LIST_HPP_INCLUDED
// Copyright 2015-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
#include <boost/mp11/integral.hpp>
#include <boost/mp11/detail/mp_list.hpp>
#include <boost/mp11/detail/mp_is_list.hpp>
#include <boost/mp11/detail/mp_append.hpp>
#include <boost/mp11/detail/mp_front.hpp>
#include <boost/mp11/detail/mp_rename.hpp>
#include <boost/mp11/detail/config.hpp>
#include <type_traits>
namespace boost
{
namespace mp11
{
// mp_list_c<T, I...>
template<class T, T... I> using mp_list_c = mp_list<std::integral_constant<T, I>...>;
// mp_is_list<L>
// in detail/mp_is_list.hpp
// mp_size<L>
namespace detail
{
template<class L> struct mp_size_impl
{
// An error "no type named 'type'" here means that the argument to mp_size is not a list
};
template<template<class...> class L, class... T> struct mp_size_impl<L<T...>>
{
using type = mp_size_t<sizeof...(T)>;
};
} // namespace detail
template<class L> using mp_size = typename detail::mp_size_impl<L>::type;
// mp_empty<L>
template<class L> using mp_empty = mp_bool< mp_size<L>::value == 0 >;
// mp_assign<L1, L2>
namespace detail
{
template<class L1, class L2> struct mp_assign_impl;
template<template<class...> class L1, class... T, template<class...> class L2, class... U> struct mp_assign_impl<L1<T...>, L2<U...>>
{
using type = L1<U...>;
};
} // namespace detail
template<class L1, class L2> using mp_assign = typename detail::mp_assign_impl<L1, L2>::type;
// mp_clear<L>
template<class L> using mp_clear = mp_assign<L, mp_list<>>;
// mp_front<L>
// in detail/mp_front.hpp
// mp_pop_front<L>
namespace detail
{
template<class L> struct mp_pop_front_impl
{
// An error "no type named 'type'" here means that the argument to mp_pop_front
// is either not a list, or is an empty list
};
template<template<class...> class L, class T1, class... T> struct mp_pop_front_impl<L<T1, T...>>
{
using type = L<T...>;
};
} // namespace detail
template<class L> using mp_pop_front = typename detail::mp_pop_front_impl<L>::type;
// mp_first<L>
template<class L> using mp_first = mp_front<L>;
// mp_rest<L>
template<class L> using mp_rest = mp_pop_front<L>;
// mp_second<L>
namespace detail
{
template<class L> struct mp_second_impl
{
// An error "no type named 'type'" here means that the argument to mp_second
// is either not a list, or has fewer than two elements
};
template<template<class...> class L, class T1, class T2, class... T> struct mp_second_impl<L<T1, T2, T...>>
{
using type = T2;
};
} // namespace detail
template<class L> using mp_second = typename detail::mp_second_impl<L>::type;
// mp_third<L>
namespace detail
{
template<class L> struct mp_third_impl
{
// An error "no type named 'type'" here means that the argument to mp_third
// is either not a list, or has fewer than three elements
};
template<template<class...> class L, class T1, class T2, class T3, class... T> struct mp_third_impl<L<T1, T2, T3, T...>>
{
using type = T3;
};
} // namespace detail
template<class L> using mp_third = typename detail::mp_third_impl<L>::type;
// mp_push_front<L, T...>
namespace detail
{
template<class L, class... T> struct mp_push_front_impl
{
// An error "no type named 'type'" here means that the first argument to mp_push_front is not a list
};
template<template<class...> class L, class... U, class... T> struct mp_push_front_impl<L<U...>, T...>
{
using type = L<T..., U...>;
};
} // namespace detail
template<class L, class... T> using mp_push_front = typename detail::mp_push_front_impl<L, T...>::type;
// mp_push_back<L, T...>
namespace detail
{
template<class L, class... T> struct mp_push_back_impl
{
// An error "no type named 'type'" here means that the first argument to mp_push_back is not a list
};
template<template<class...> class L, class... U, class... T> struct mp_push_back_impl<L<U...>, T...>
{
using type = L<U..., T...>;
};
} // namespace detail
template<class L, class... T> using mp_push_back = typename detail::mp_push_back_impl<L, T...>::type;
// mp_rename<L, B>
// mp_apply<F, L>
// mp_apply_q<Q, L>
// in detail/mp_rename.hpp
// mp_replace_front<L, T>
namespace detail
{
template<class L, class T> struct mp_replace_front_impl
{
// An error "no type named 'type'" here means that the first argument to mp_replace_front
// is either not a list, or is an empty list
};
template<template<class...> class L, class U1, class... U, class T> struct mp_replace_front_impl<L<U1, U...>, T>
{
using type = L<T, U...>;
};
} // namespace detail
template<class L, class T> using mp_replace_front = typename detail::mp_replace_front_impl<L, T>::type;
// mp_replace_first<L, T>
template<class L, class T> using mp_replace_first = typename detail::mp_replace_front_impl<L, T>::type;
// mp_replace_second<L, T>
namespace detail
{
template<class L, class T> struct mp_replace_second_impl
{
// An error "no type named 'type'" here means that the first argument to mp_replace_second
// is either not a list, or has fewer than two elements
};
template<template<class...> class L, class U1, class U2, class... U, class T> struct mp_replace_second_impl<L<U1, U2, U...>, T>
{
using type = L<U1, T, U...>;
};
} // namespace detail
template<class L, class T> using mp_replace_second = typename detail::mp_replace_second_impl<L, T>::type;
// mp_replace_third<L, T>
namespace detail
{
template<class L, class T> struct mp_replace_third_impl
{
// An error "no type named 'type'" here means that the first argument to mp_replace_third
// is either not a list, or has fewer than three elements
};
template<template<class...> class L, class U1, class U2, class U3, class... U, class T> struct mp_replace_third_impl<L<U1, U2, U3, U...>, T>
{
using type = L<U1, U2, T, U...>;
};
} // namespace detail
template<class L, class T> using mp_replace_third = typename detail::mp_replace_third_impl<L, T>::type;
// mp_transform_front<L, F>
namespace detail
{
template<class L, template<class...> class F> struct mp_transform_front_impl
{
// An error "no type named 'type'" here means that the first argument to mp_transform_front
// is either not a list, or is an empty list
};
template<template<class...> class L, class U1, class... U, template<class...> class F> struct mp_transform_front_impl<L<U1, U...>, F>
{
using type = L<F<U1>, U...>;
};
} // namespace detail
template<class L, template<class...> class F> using mp_transform_front = typename detail::mp_transform_front_impl<L, F>::type;
template<class L, class Q> using mp_transform_front_q = mp_transform_front<L, Q::template fn>;
// mp_transform_first<L, F>
template<class L, template<class...> class F> using mp_transform_first = typename detail::mp_transform_front_impl<L, F>::type;
template<class L, class Q> using mp_transform_first_q = mp_transform_first<L, Q::template fn>;
// mp_transform_second<L, F>
namespace detail
{
template<class L, template<class...> class F> struct mp_transform_second_impl
{
// An error "no type named 'type'" here means that the first argument to mp_transform_second
// is either not a list, or has fewer than two elements
};
template<template<class...> class L, class U1, class U2, class... U, template<class...> class F> struct mp_transform_second_impl<L<U1, U2, U...>, F>
{
using type = L<U1, F<U2>, U...>;
};
} // namespace detail
template<class L, template<class...> class F> using mp_transform_second = typename detail::mp_transform_second_impl<L, F>::type;
template<class L, class Q> using mp_transform_second_q = mp_transform_second<L, Q::template fn>;
// mp_transform_third<L, F>
namespace detail
{
template<class L, template<class...> class F> struct mp_transform_third_impl
{
// An error "no type named 'type'" here means that the first argument to mp_transform_third
// is either not a list, or has fewer than three elements
};
template<template<class...> class L, class U1, class U2, class U3, class... U, template<class...> class F> struct mp_transform_third_impl<L<U1, U2, U3, U...>, F>
{
using type = L<U1, U2, F<U3>, U...>;
};
} // namespace detail
template<class L, template<class...> class F> using mp_transform_third = typename detail::mp_transform_third_impl<L, F>::type;
template<class L, class Q> using mp_transform_third_q = mp_transform_third<L, Q::template fn>;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_LIST_HPP_INCLUDED

View File

@@ -0,0 +1,119 @@
#ifndef BOOST_MP11_MAP_HPP_INCLUDED
#define BOOST_MP11_MAP_HPP_INCLUDED
// Copyright 2015-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
#include <boost/mp11/detail/mp_map_find.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/function.hpp>
#include <boost/mp11/set.hpp>
#include <type_traits>
namespace boost
{
namespace mp11
{
// 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_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> >;
// mp_map_replace<M, T>
namespace detail
{
template<class M, class T> struct mp_map_replace_impl;
template<template<class...> class M, class... U, class T> struct mp_map_replace_impl<M<U...>, T>
{
using K = mp_first<T>;
// mp_replace_if is inlined here using a struct _f because of msvc-14.0
template<class V> struct _f { using type = mp_if< std::is_same<mp_first<V>, K>, T, V >; };
using type = mp_if< mp_map_contains<M<U...>, K>, M<typename _f<U>::type...>, M<U..., T> >;
};
} // namespace detail
template<class M, class T> using mp_map_replace = typename detail::mp_map_replace_impl<M, T>::type;
// mp_map_update<M, T, F>
namespace detail
{
template<class M, class T, template<class...> class F> struct mp_map_update_impl
{
template<class U> using _f = std::is_same<mp_first<T>, mp_first<U>>;
// _f3<L<X, Y...>> -> L<X, F<X, Y...>>
template<class L> using _f3 = mp_assign<L, mp_list<mp_first<L>, mp_rename<L, F> > >;
using type = mp_if< mp_map_contains<M, mp_first<T>>, mp_transform_if<_f, _f3, M>, mp_push_back<M, T> >;
};
} // namespace detail
template<class M, class T, template<class...> class F> using mp_map_update = typename detail::mp_map_update_impl<M, T, F>::type;
template<class M, class T, class Q> using mp_map_update_q = mp_map_update<M, T, Q::template fn>;
// mp_map_erase<M, K>
namespace detail
{
template<class M, class K> struct mp_map_erase_impl
{
template<class T> using _f = std::is_same<mp_first<T>, K>;
using type = mp_remove_if<M, _f>;
};
} // namespace detail
template<class M, class K> using mp_map_erase = typename detail::mp_map_erase_impl<M, K>::type;
// mp_map_keys<M>
template<class M> using mp_map_keys = mp_transform<mp_first, M>;
// mp_is_map<M>
namespace detail
{
template<class L> struct mp_is_map_element: mp_false
{
};
template<template<class...> class L, class T1, class... T> struct mp_is_map_element<L<T1, T...>>: mp_true
{
};
template<class M> using mp_keys_are_set = mp_is_set<mp_map_keys<M>>;
template<class M> struct mp_is_map_impl
{
using type = mp_false;
};
template<template<class...> class M, class... T> struct mp_is_map_impl<M<T...>>
{
using type = mp_eval_if<mp_not<mp_all<mp_is_map_element<T>...>>, mp_false, mp_keys_are_set, M<T...>>;
};
} // namespace detail
template<class M> using mp_is_map = typename detail::mp_is_map_impl<M>::type;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_MAP_HPP_INCLUDED

View File

@@ -0,0 +1,14 @@
#ifndef BOOST_MP11_MPL_HPP_INCLUDED
#define BOOST_MP11_MPL_HPP_INCLUDED
// Copyright 2017, 2019 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
#include <boost/mp11/mpl_list.hpp>
#include <boost/mp11/mpl_tuple.hpp>
#endif // #ifndef BOOST_MP11_MPL_HPP_INCLUDED

View File

@@ -0,0 +1,28 @@
#ifndef BOOST_MP11_MPL_LIST_HPP_INCLUDED
#define BOOST_MP11_MPL_LIST_HPP_INCLUDED
// Copyright 2017, 2019 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
#include <boost/mp11/detail/mpl_common.hpp>
namespace boost
{
namespace mpl
{
template< typename Sequence > struct sequence_tag;
template<class... T> struct sequence_tag<mp11::mp_list<T...>>
{
using type = aux::mp11_tag;
};
} // namespace mpl
} // namespace boost
#endif // #ifndef BOOST_MP11_MPL_LIST_HPP_INCLUDED

View File

@@ -0,0 +1,29 @@
#ifndef BOOST_MP11_MPL_TUPLE_HPP_INCLUDED
#define BOOST_MP11_MPL_TUPLE_HPP_INCLUDED
// Copyright 2017, 2019 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
#include <boost/mp11/detail/mpl_common.hpp>
#include <tuple>
namespace boost
{
namespace mpl
{
template< typename Sequence > struct sequence_tag;
template<class... T> struct sequence_tag<std::tuple<T...>>
{
using type = aux::mp11_tag;
};
} // namespace mpl
} // namespace boost
#endif // #ifndef BOOST_MP11_MPL_TUPLE_HPP_INCLUDED

View File

@@ -0,0 +1,188 @@
#ifndef BOOST_MP11_SET_HPP_INCLUDED
#define BOOST_MP11_SET_HPP_INCLUDED
// Copyright 2015, 2019 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
#include <boost/mp11/utility.hpp>
#include <boost/mp11/function.hpp>
#include <boost/mp11/detail/mp_list.hpp>
#include <boost/mp11/detail/mp_append.hpp>
#include <boost/mp11/detail/mp_copy_if.hpp>
#include <boost/mp11/detail/mp_remove_if.hpp>
#include <boost/mp11/detail/mp_is_list.hpp>
#include <type_traits>
namespace boost
{
namespace mp11
{
// mp_set_contains<S, V>
namespace detail
{
template<class S, class V> struct mp_set_contains_impl
{
};
template<template<class...> class L, class... T, class V> struct mp_set_contains_impl<L<T...>, V>
{
using type = mp_to_bool<std::is_base_of<mp_identity<V>, mp_inherit<mp_identity<T>...> > >;
};
} // namespace detail
template<class S, class V> using mp_set_contains = typename detail::mp_set_contains_impl<S, V>::type;
// mp_set_push_back<S, T...>
namespace detail
{
template<class S, class... T> struct mp_set_push_back_impl
{
};
template<template<class...> class L, class... U> struct mp_set_push_back_impl<L<U...>>
{
using type = L<U...>;
};
template<template<class...> class L, class... U, class T1, class... T> struct mp_set_push_back_impl<L<U...>, T1, T...>
{
using S = mp_if<mp_set_contains<L<U...>, T1>, L<U...>, L<U..., T1>>;
using type = typename mp_set_push_back_impl<S, T...>::type;
};
} // namespace detail
template<class S, class... T> using mp_set_push_back = typename detail::mp_set_push_back_impl<S, T...>::type;
// mp_set_push_front<S, T...>
namespace detail
{
template<class S, class... T> struct mp_set_push_front_impl
{
};
template<template<class...> class L, class... U> struct mp_set_push_front_impl<L<U...>>
{
using type = L<U...>;
};
template<template<class...> class L, class... U, class T1> struct mp_set_push_front_impl<L<U...>, T1>
{
using type = mp_if<mp_set_contains<L<U...>, T1>, L<U...>, L<T1, U...>>;
};
template<template<class...> class L, class... U, class T1, class... T> struct mp_set_push_front_impl<L<U...>, T1, T...>
{
using S = typename mp_set_push_front_impl<L<U...>, T...>::type;
using type = typename mp_set_push_front_impl<S, T1>::type;
};
} // namespace detail
template<class S, class... T> using mp_set_push_front = typename detail::mp_set_push_front_impl<S, T...>::type;
// mp_is_set<S>
namespace detail
{
template<class S> struct mp_is_set_impl
{
using type = mp_false;
};
template<template<class...> class L, class... T> struct mp_is_set_impl<L<T...>>
{
using type = mp_to_bool<std::is_same<mp_list<T...>, mp_set_push_back<mp_list<>, T...> > >;
};
} // namespace detail
template<class S> using mp_is_set = typename detail::mp_is_set_impl<S>::type;
// mp_set_union<L...>
namespace detail
{
template<class... L> struct mp_set_union_impl
{
};
template<> struct mp_set_union_impl<>
{
using type = mp_list<>;
};
template<template<class...> class L, class... T> struct mp_set_union_impl<L<T...>>
{
using type = L<T...>;
};
template<template<class...> class L1, class... T1, template<class...> class L2, class... T2> struct mp_set_union_impl<L1<T1...>, L2<T2...>>
{
using type = mp_set_push_back<L1<T1...>, T2...>;
};
template<class L1, class... L> using mp_set_union_ = typename mp_set_union_impl<L1, mp_append<mp_list<>, L...>>::type;
template<class L1, class L2, class L3, class... L> struct mp_set_union_impl<L1, L2, L3, L...>: mp_defer<mp_set_union_, L1, L2, L3, L...>
{
};
} // namespace detail
template<class... L> using mp_set_union = typename detail::mp_set_union_impl<L...>::type;
// mp_set_intersection<S...>
namespace detail
{
template<class... S> struct in_all_sets
{
template<class T> using fn = mp_all< mp_set_contains<S, T>... >;
};
template<class L, class... S> using mp_set_intersection_ = mp_if< mp_all<mp_is_list<S>...>, mp_copy_if_q<L, detail::in_all_sets<S...>> >;
template<class... S> struct mp_set_intersection_impl
{
};
template<> struct mp_set_intersection_impl<>
{
using type = mp_list<>;
};
template<class L, class... S> struct mp_set_intersection_impl<L, S...>: mp_defer<mp_set_intersection_, L, S...>
{
};
} // namespace detail
template<class... S> using mp_set_intersection = typename detail::mp_set_intersection_impl<S...>::type;
// mp_set_difference<L, S...>
namespace detail
{
template<class... S> struct in_any_set
{
template<class T> using fn = mp_any< mp_set_contains<S, T>... >;
};
} // namespace detail
template<class L, class... S> using mp_set_difference = mp_if< mp_all<mp_is_list<S>...>, mp_remove_if_q<L, detail::in_any_set<S...>> >;
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_SET_HPP_INCLUDED

View File

@@ -0,0 +1,183 @@
#ifndef BOOST_MP11_TUPLE_HPP_INCLUDED
#define BOOST_MP11_TUPLE_HPP_INCLUDED
// Copyright 2015-2020 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
#include <boost/mp11/integer_sequence.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/function.hpp>
#include <boost/mp11/detail/config.hpp>
#include <tuple>
#include <utility>
#include <type_traits>
#include <cstddef>
#if BOOST_MP11_MSVC
# pragma warning( push )
# pragma warning( disable: 4100 ) // unreferenced formal parameter 'tp'
#endif
namespace boost
{
namespace mp11
{
// tuple_apply
namespace detail
{
using std::get;
template<class F, class Tp, std::size_t... J> BOOST_MP11_CONSTEXPR auto tuple_apply_impl( F && f, Tp && tp, integer_sequence<std::size_t, J...> )
-> decltype( std::forward<F>(f)( get<J>(std::forward<Tp>(tp))... ) )
{
return std::forward<F>(f)( get<J>(std::forward<Tp>(tp))... );
}
} // namespace detail
template<class F, class Tp,
class Seq = make_index_sequence<std::tuple_size<typename std::remove_reference<Tp>::type>::value>>
BOOST_MP11_CONSTEXPR auto tuple_apply( F && f, Tp && tp )
-> decltype( detail::tuple_apply_impl( std::forward<F>(f), std::forward<Tp>(tp), Seq() ) )
{
return detail::tuple_apply_impl( std::forward<F>(f), std::forward<Tp>(tp), Seq() );
}
// construct_from_tuple
namespace detail
{
template<class T, class Tp, std::size_t... J> BOOST_MP11_CONSTEXPR T construct_from_tuple_impl( Tp && tp, integer_sequence<std::size_t, J...> )
{
return T( get<J>(std::forward<Tp>(tp))... );
}
} // namespace detail
template<class T, class Tp,
class Seq = make_index_sequence<std::tuple_size<typename std::remove_reference<Tp>::type>::value>>
BOOST_MP11_CONSTEXPR T construct_from_tuple( Tp && tp )
{
return detail::construct_from_tuple_impl<T>( std::forward<Tp>(tp), Seq() );
}
// tuple_for_each
namespace detail
{
template<class Tp, std::size_t... J, class F> BOOST_MP11_CONSTEXPR F tuple_for_each_impl( Tp && tp, integer_sequence<std::size_t, J...>, F && f )
{
using A = int[sizeof...(J)];
return (void)A{ ((void)f(get<J>(std::forward<Tp>(tp))), 0)... }, std::forward<F>(f);
}
template<class Tp, class F> BOOST_MP11_CONSTEXPR F tuple_for_each_impl( Tp && /*tp*/, integer_sequence<std::size_t>, F && f )
{
return std::forward<F>(f);
}
} // namespace detail
template<class Tp, class F> BOOST_MP11_CONSTEXPR F tuple_for_each( Tp && tp, F && f )
{
using seq = make_index_sequence<std::tuple_size<typename std::remove_reference<Tp>::type>::value>;
return detail::tuple_for_each_impl( std::forward<Tp>(tp), seq(), std::forward<F>(f) );
}
// tuple_transform
namespace detail
{
// std::forward_as_tuple is not constexpr in C++11 or libstdc++ 5.x
template<class... T> BOOST_MP11_CONSTEXPR auto tp_forward_r( T&&... t ) -> std::tuple<T&&...>
{
return std::tuple<T&&...>( std::forward<T>( t )... );
}
template<class... T> BOOST_MP11_CONSTEXPR auto tp_forward_v( T&&... t ) -> std::tuple<T...>
{
return std::tuple<T...>( std::forward<T>( t )... );
}
template<std::size_t J, class... Tp>
BOOST_MP11_CONSTEXPR auto tp_extract( Tp&&... tp )
-> decltype( tp_forward_r( get<J>( std::forward<Tp>( tp ) )... ) )
{
return tp_forward_r( get<J>( std::forward<Tp>( tp ) )... );
}
#if !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 )
template<class F, class... Tp, std::size_t... J>
BOOST_MP11_CONSTEXPR auto tuple_transform_impl( integer_sequence<std::size_t, J...>, F const& f, Tp&&... tp )
-> decltype( tp_forward_v( tuple_apply( f, tp_extract<J>( std::forward<Tp>(tp)... ) )... ) )
{
return tp_forward_v( tuple_apply( f, tp_extract<J>( std::forward<Tp>(tp)... ) )... );
}
#else
template<class F, class Tp1, std::size_t... J>
BOOST_MP11_CONSTEXPR auto tuple_transform_impl( integer_sequence<std::size_t, J...>, F const& f, Tp1&& tp1 )
-> decltype( tp_forward_v( f( get<J>( std::forward<Tp1>(tp1) ) )... ) )
{
return tp_forward_v( f( get<J>( std::forward<Tp1>(tp1) ) )... );
}
template<class F, class Tp1, class Tp2, std::size_t... J>
BOOST_MP11_CONSTEXPR auto tuple_transform_impl( integer_sequence<std::size_t, J...>, F const& f, Tp1&& tp1, Tp2&& tp2 )
-> decltype( tp_forward_v( f( get<J>( std::forward<Tp1>(tp1) ), get<J>( std::forward<Tp2>(tp2) ) )... ) )
{
return tp_forward_v( f( get<J>( std::forward<Tp1>(tp1) ), get<J>( std::forward<Tp2>(tp2) ) )... );
}
template<class F, class Tp1, class Tp2, class Tp3, std::size_t... J>
BOOST_MP11_CONSTEXPR auto tuple_transform_impl( integer_sequence<std::size_t, J...>, F const& f, Tp1&& tp1, Tp2&& tp2, Tp3&& tp3 )
-> decltype( tp_forward_v( f( get<J>( std::forward<Tp1>(tp1) ), get<J>( std::forward<Tp2>(tp2) ), get<J>( std::forward<Tp3>(tp3) ) )... ) )
{
return tp_forward_v( f( get<J>( std::forward<Tp1>(tp1) ), get<J>( std::forward<Tp2>(tp2) ), get<J>( std::forward<Tp3>(tp3) ) )... );
}
#endif // !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 )
} // namespace detail
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1910 )
template<class F, class Tp1, class... Tp,
class Seq = make_index_sequence<std::tuple_size<typename std::remove_reference<Tp1>::type>::value>>
BOOST_MP11_CONSTEXPR auto tuple_transform( F const& f, Tp1&& tp1, Tp&&... tp )
-> decltype( detail::tuple_transform_impl( Seq(), f, std::forward<Tp1>(tp1), std::forward<Tp>(tp)... ) )
{
return detail::tuple_transform_impl( Seq(), f, std::forward<Tp1>(tp1), std::forward<Tp>(tp)... );
}
#else
template<class F, class... Tp,
class Z = mp_list<mp_size_t<std::tuple_size<typename std::remove_reference<Tp>::type>::value>...>,
class E = mp_if<mp_apply<mp_same, Z>, mp_front<Z>>,
class Seq = make_index_sequence<E::value>>
BOOST_MP11_CONSTEXPR auto tuple_transform( F const& f, Tp&&... tp )
-> decltype( detail::tuple_transform_impl( Seq(), f, std::forward<Tp>(tp)... ) )
{
return detail::tuple_transform_impl( Seq(), f, std::forward<Tp>(tp)... );
}
#endif // BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1910 )
} // namespace mp11
} // namespace boost
#if BOOST_MP11_MSVC
# pragma warning( pop )
#endif
#endif // #ifndef BOOST_TUPLE_HPP_INCLUDED

View File

@@ -0,0 +1,263 @@
#ifndef BOOST_MP11_UTILITY_HPP_INCLUDED
#define BOOST_MP11_UTILITY_HPP_INCLUDED
// Copyright 2015-2020 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
#include <boost/mp11/integral.hpp>
#include <boost/mp11/detail/mp_list.hpp>
#include <boost/mp11/detail/mp_fold.hpp>
#include <boost/mp11/detail/mp_front.hpp>
#include <boost/mp11/detail/mp_rename.hpp>
#include <boost/mp11/detail/config.hpp>
namespace boost
{
namespace mp11
{
// mp_identity
template<class T> struct mp_identity
{
using type = T;
};
// mp_identity_t
template<class T> using mp_identity_t = typename mp_identity<T>::type;
// mp_inherit
template<class... T> struct mp_inherit: T... {};
// mp_if, mp_if_c
namespace detail
{
template<bool C, class T, class... E> struct mp_if_c_impl
{
};
template<class T, class... E> struct mp_if_c_impl<true, T, E...>
{
using type = T;
};
template<class T, class E> struct mp_if_c_impl<false, T, E>
{
using type = E;
};
} // namespace detail
template<bool C, class T, class... E> using mp_if_c = typename detail::mp_if_c_impl<C, T, E...>::type;
template<class C, class T, class... E> using mp_if = typename detail::mp_if_c_impl<static_cast<bool>(C::value), T, E...>::type;
// mp_valid
#if BOOST_MP11_WORKAROUND( BOOST_MP11_INTEL, != 0 ) // tested at 1800
// contributed by Roland Schulz in https://github.com/boostorg/mp11/issues/17
namespace detail
{
template<class...> using void_t = void;
template<class, template<class...> class F, class... T>
struct mp_valid_impl: mp_false {};
template<template<class...> class F, class... T>
struct mp_valid_impl<void_t<F<T...>>, F, T...>: mp_true {};
} // namespace detail
template<template<class...> class F, class... T> using mp_valid = typename detail::mp_valid_impl<void, F, T...>;
#else
// implementation by Bruno Dutra (by the name is_evaluable)
namespace detail
{
template<template<class...> class F, class... T> struct mp_valid_impl
{
template<template<class...> class G, class = G<T...>> static mp_true check(int);
template<template<class...> class> static mp_false check(...);
using type = decltype(check<F>(0));
};
} // namespace detail
template<template<class...> class F, class... T> using mp_valid = typename detail::mp_valid_impl<F, T...>::type;
#endif
template<class Q, class... T> using mp_valid_q = mp_valid<Q::template fn, T...>;
// mp_defer
namespace detail
{
template<template<class...> class F, class... T> struct mp_defer_impl
{
using type = F<T...>;
};
struct mp_no_type
{
};
#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 )
template<template<class...> class F, class... T> struct mp_defer_cuda_workaround
{
using type = mp_if<mp_valid<F, T...>, detail::mp_defer_impl<F, T...>, detail::mp_no_type>;
};
#endif
} // namespace detail
#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 )
template<template<class...> class F, class... T> using mp_defer = typename detail::mp_defer_cuda_workaround< F, T...>::type;
#else
template<template<class...> class F, class... T> using mp_defer = mp_if<mp_valid<F, T...>, detail::mp_defer_impl<F, T...>, detail::mp_no_type>;
#endif
// mp_eval_if, mp_eval_if_c
namespace detail
{
template<bool C, class T, template<class...> class F, class... U> struct mp_eval_if_c_impl;
template<class T, template<class...> class F, class... U> struct mp_eval_if_c_impl<true, T, F, U...>
{
using type = T;
};
template<class T, template<class...> class F, class... U> struct mp_eval_if_c_impl<false, T, F, U...>: mp_defer<F, U...>
{
};
} // namespace detail
template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c = typename detail::mp_eval_if_c_impl<C, T, F, U...>::type;
template<class C, class T, template<class...> class F, class... U> using mp_eval_if = typename detail::mp_eval_if_c_impl<static_cast<bool>(C::value), T, F, U...>::type;
template<class C, class T, class Q, class... U> using mp_eval_if_q = typename detail::mp_eval_if_c_impl<static_cast<bool>(C::value), T, Q::template fn, U...>::type;
// mp_eval_if_not
template<class C, class T, template<class...> class F, class... U> using mp_eval_if_not = mp_eval_if<mp_not<C>, T, F, U...>;
template<class C, class T, class Q, class... U> using mp_eval_if_not_q = mp_eval_if<mp_not<C>, T, Q::template fn, U...>;
// mp_eval_or
template<class T, template<class...> class F, class... U> using mp_eval_or = mp_eval_if_not<mp_valid<F, U...>, T, F, U...>;
template<class T, class Q, class... U> using mp_eval_or_q = mp_eval_or<T, Q::template fn, U...>;
// mp_valid_and_true
template<template<class...> class F, class... T> using mp_valid_and_true = mp_eval_or<mp_false, F, T...>;
template<class Q, class... T> using mp_valid_and_true_q = mp_valid_and_true<Q::template fn, T...>;
// mp_cond
// so elegant; so doesn't work
// template<class C, class T, class... E> using mp_cond = mp_eval_if<C, T, mp_cond, E...>;
namespace detail
{
template<class C, class T, class... E> struct mp_cond_impl;
} // namespace detail
template<class C, class T, class... E> using mp_cond = typename detail::mp_cond_impl<C, T, E...>::type;
namespace detail
{
template<class C, class T, class... E> using mp_cond_ = mp_eval_if<C, T, mp_cond, E...>;
template<class C, class T, class... E> struct mp_cond_impl: mp_defer<mp_cond_, C, T, E...>
{
};
} // namespace detail
// mp_quote
template<template<class...> class F> struct mp_quote
{
// the indirection through mp_defer works around the language inability
// to expand T... into a fixed parameter list of an alias template
template<class... T> using fn = typename mp_defer<F, T...>::type;
};
// mp_quote_trait
template<template<class...> class F> struct mp_quote_trait
{
template<class... T> using fn = typename F<T...>::type;
};
// mp_invoke_q
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 )
namespace detail
{
template<class Q, class... T> struct mp_invoke_q_impl: mp_defer<Q::template fn, T...> {};
} // namespace detail
template<class Q, class... T> using mp_invoke_q = typename detail::mp_invoke_q_impl<Q, T...>::type;
#elif BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 50000 )
template<class Q, class... T> using mp_invoke_q = typename mp_defer<Q::template fn, T...>::type;
#else
template<class Q, class... T> using mp_invoke_q = typename Q::template fn<T...>;
#endif
// mp_not_fn<P>
template<template<class...> class P> struct mp_not_fn
{
template<class... T> using fn = mp_not< mp_invoke_q<mp_quote<P>, T...> >;
};
template<class Q> using mp_not_fn_q = mp_not_fn<Q::template fn>;
// mp_compose
namespace detail
{
template<class L, class Q> using mp_compose_helper = mp_list< mp_apply_q<Q, L> >;
} // namespace detail
#if !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 )
template<template<class...> class... F> struct mp_compose
{
template<class... T> using fn = mp_front< mp_fold<mp_list<mp_quote<F>...>, mp_list<T...>, detail::mp_compose_helper> >;
};
#endif
template<class... Q> struct mp_compose_q
{
template<class... T> using fn = mp_front< mp_fold<mp_list<Q...>, mp_list<T...>, detail::mp_compose_helper> >;
};
} // namespace mp11
} // namespace boost
#endif // #ifndef BOOST_MP11_UTILITY_HPP_INCLUDED

View File

@@ -0,0 +1,16 @@
#ifndef BOOST_MP11_VERSION_HPP_INCLUDED
#define BOOST_MP11_VERSION_HPP_INCLUDED
// Copyright 2019 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
// Same format as BOOST_VERSION:
// major * 100000 + minor * 100 + patch
#define BOOST_MP11_VERSION 107900
#endif // #ifndef BOOST_MP11_VERSION_HPP_INCLUDED

View File

@@ -0,0 +1,15 @@
<html>
<head>
<meta http-equiv="refresh" content="0; URL=doc/html/mp11.html">
</head>
<body>
Automatic redirection failed, please go to
<a href="doc/html/mp11.html">doc/html/mp11.html</a>.
</body>
</html>
<!--
<09> Copyright Beman Dawes, 2001
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
-->

View File

@@ -0,0 +1,15 @@
{
"key": "mp11",
"name": "Mp11",
"authors": [
"Peter Dimov"
],
"maintainers": [
"Peter Dimov <pdimov -at- gmail.com>"
],
"description": "A C++11 metaprogramming library.",
"category": [
"Metaprogramming"
],
"cxxstd": "11"
}

View File

@@ -0,0 +1,12 @@
# Copyright 2018 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
include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
if(HAVE_BOOST_TEST)
boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::mp11 Boost::core)
boost_test(SOURCES check_cmake_version.cpp ARGUMENTS ${PROJECT_VERSION} LINK_LIBRARIES Boost::core Boost::config)
endif()

View File

@@ -0,0 +1,235 @@
# Boost.Mp11 Library Test Jamfile
#
# Copyright 2015-2019 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 testing ;
import ../../config/checks/config : requires ;
project
: requirements
[ requires cxx11_variadic_templates cxx11_template_aliases cxx11_decltype cxx11_hdr_tuple ]
<warnings>extra
<toolset>msvc:<warnings-as-errors>on
<toolset>gcc:<warnings-as-errors>on
<toolset>clang:<warnings-as-errors>on
;
# include-only
compile mp11.cpp ;
# list
run mp_size.cpp ;
run mp_empty.cpp ;
run mp_front.cpp ;
run mp_pop_front.cpp ;
run mp_second.cpp ;
run mp_third.cpp ;
run mp_push_front.cpp ;
run mp_push_back.cpp ;
run mp_rename.cpp ;
run mp_append.cpp ;
run mp_append_2.cpp ;
run mp_append_sf.cpp ;
run mp_replace_front.cpp ;
run mp_replace_second.cpp ;
run mp_replace_third.cpp ;
run mp_apply_q.cpp ;
run mp_is_list.cpp ;
run mp_list_c.cpp ;
run mp_transform_front.cpp ;
run mp_transform_second.cpp ;
run mp_transform_third.cpp ;
# algorithm
run mp_assign.cpp ;
run mp_clear.cpp ;
run mp_transform.cpp ;
run mp_transform_q.cpp ;
run mp_transform_sf.cpp ;
run mp_transform_if.cpp ;
run mp_transform_if_q.cpp ;
run mp_filter.cpp ;
run mp_fill.cpp ;
run mp_count.cpp ;
run mp_count_if.cpp ;
run mp_count_if_q.cpp ;
run mp_contains.cpp ;
run mp_starts_with.cpp ;
run mp_starts_with_sf.cpp ;
run mp_repeat.cpp ;
run mp_product.cpp ;
run mp_drop.cpp ;
run mp_iota.cpp ;
run mp_at.cpp ;
run mp_at_sf.cpp : : : <toolset>gcc-4.7:<warnings>all ;
run mp_take.cpp ;
run mp_replace.cpp ;
run mp_replace_if.cpp ;
run mp_replace_if_q.cpp ;
run mp_copy_if.cpp ;
run mp_copy_if_q.cpp ;
run mp_remove.cpp ;
run mp_remove_if.cpp ;
run mp_remove_if_q.cpp ;
run mp_partition.cpp ;
run mp_partition_q.cpp ;
run mp_sort.cpp ;
run mp_sort_q.cpp ;
run mp_find.cpp ;
run mp_find_if.cpp ;
run mp_find_if_q.cpp ;
run mp_reverse.cpp ;
run mp_fold.cpp ;
run mp_fold_q.cpp ;
run mp_reverse_fold.cpp ;
run mp_reverse_fold_q.cpp ;
run mp_unique.cpp ;
run mp_unique_if.cpp ;
run mp_unique_if_q.cpp ;
run mp_all_of.cpp ;
run mp_all_of_q.cpp ;
run mp_any_of.cpp ;
run mp_any_of_q.cpp ;
run mp_none_of.cpp ;
run mp_none_of_q.cpp ;
run mp_replace_at.cpp ;
run mp_replace_at_c.cpp ;
run mp_for_each.cpp ;
run mp_insert.cpp ;
run mp_erase.cpp ;
run mp_with_index.cpp ;
run mp_with_index_cx.cpp ;
run mp_from_sequence.cpp ;
run mp_min_element.cpp ;
run mp_min_element_q.cpp ;
run mp_max_element.cpp ;
run mp_max_element_q.cpp ;
run mp_nth_element.cpp ;
run mp_nth_element_q.cpp ;
run mp_back.cpp ;
run mp_pop_back.cpp ;
run mp_flatten.cpp ;
run mp_rotate_left.cpp ;
run mp_rotate_right.cpp ;
run mp_power_set.cpp ;
run mp_partial_sum.cpp ;
run mp_iterate.cpp ;
run mp_pairwise_fold.cpp ;
run mp_pairwise_fold_q.cpp ;
run mp_intersperse.cpp ;
run mp_split.cpp ;
run mp_join.cpp ;
# integral
run integral.cpp ;
# utility
run mp_identity.cpp ;
run mp_inherit.cpp ;
run mp_if.cpp ;
run mp_if_sf.cpp ;
run mp_eval_if.cpp ;
run mp_eval_if_sf.cpp ;
run mp_valid.cpp ;
run mp_defer.cpp ;
run mp_quote.cpp ;
run mp_invoke_q.cpp ;
run mp_invoke_q_sf.cpp ;
run mp_quote_trait.cpp ;
run mp_cond.cpp ;
run mp_cond_sf.cpp ;
run mp_not_fn.cpp ;
run mp_eval_if_not.cpp ;
run mp_eval_or.cpp ;
run mp_compose.cpp ;
run mp_valid_and_true.cpp ;
# integer_sequence
run integer_sequence.cpp ;
# tuple
run tuple_for_each.cpp ;
compile tuple_for_each_cx.cpp ;
run tuple_apply.cpp ;
compile tuple_apply_cx.cpp ;
run construct_from_tuple.cpp ;
compile construct_from_tuple_cx.cpp ;
run tuple_transform.cpp ;
run tuple_transform_2.cpp ;
compile tuple_transform_cx.cpp ;
# set
run mp_set_contains.cpp ;
run mp_set_push_back.cpp ;
run mp_set_push_front.cpp ;
run mp_is_set.cpp ;
run mp_set_union.cpp ;
run mp_set_union_sf.cpp ;
run mp_set_difference.cpp ;
run mp_set_difference_sf.cpp ;
run mp_set_intersection.cpp ;
run mp_set_intersection_sf.cpp ;
# function
run mp_all.cpp ;
run mp_all_2.cpp ;
run mp_and.cpp ;
run mp_any.cpp ;
run mp_any_2.cpp ;
run mp_or.cpp ;
run mp_same.cpp ;
run mp_plus.cpp ;
run mp_less.cpp ;
run mp_min.cpp ;
run mp_max.cpp ;
run mp_similar.cpp ;
# map
run mp_map_find.cpp ;
run mp_map_find_2.cpp ;
run mp_map_find_3.cpp ;
run mp_map_contains.cpp ;
run mp_map_insert.cpp ;
run mp_map_replace.cpp ;
run mp_map_erase.cpp ;
run mp_map_update.cpp ;
run mp_map_update_q.cpp ;
run mp_map_keys.cpp ;
run mp_is_map.cpp ;
# bind
run mp_bind.cpp ;
run mp_bind_q.cpp ;
run mp_bind_front.cpp ;
run mp_bind_back.cpp ;
# mpl
run mpl.cpp : ;
run mpl_list.cpp : ;
run mpl_tuple.cpp : ;
# version
run version.cpp ;
run mp11_version.cpp ;
run list_version.cpp ;
run algorithm_version.cpp ;
run integral_version.cpp ;
run utility_version.cpp ;
run function_version.cpp ;
run map_version.cpp ;
run set_version.cpp ;
run bind_version.cpp ;
run integer_sequence_version.cpp ;
run tuple_version.cpp ;
run mpl_version.cpp ;
# quick (for CI)
alias quick : mp11 mp_size ;
explicit quick ;

View File

@@ -0,0 +1,17 @@
// Copyright 2019 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
#include <boost/mp11/algorithm.hpp>
#include <boost/version.hpp>
#include <boost/core/lightweight_test.hpp>
int main()
{
BOOST_TEST_EQ( BOOST_MP11_VERSION, BOOST_VERSION );
return boost::report_errors();
}

View File

@@ -0,0 +1,17 @@
// Copyright 2019 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
#include <boost/mp11/bind.hpp>
#include <boost/version.hpp>
#include <boost/core/lightweight_test.hpp>
int main()
{
BOOST_TEST_EQ( BOOST_MP11_VERSION, BOOST_VERSION );
return boost::report_errors();
}

View File

@@ -0,0 +1,27 @@
// Check whether the version in CMakeLists.txt is up to date
//
// Copyright 2018 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
#include <boost/core/lightweight_test.hpp>
#include <boost/version.hpp>
#include <cstdio>
int main( int ac, char const* av[] )
{
BOOST_TEST_EQ( ac, 2 );
if( ac >= 2 )
{
char version[ 64 ];
std::sprintf( version, "%d.%d.%d", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100 );
BOOST_TEST_CSTR_EQ( av[1], version );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,17 @@
# Copyright 2018 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
cmake_minimum_required(VERSION 3.5...3.16)
project(cmake_install_test LANGUAGES CXX)
find_package(boost_mp11 REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main Boost::mp11)
enable_testing()
add_test(NAME main COMMAND main)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)

View File

@@ -0,0 +1,12 @@
// Copyright 2018 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
#include <boost/mp11.hpp>
using namespace boost::mp11;
int main()
{
using L1 = mp_list<int, float, int, float>;
return mp_size<mp_unique<L1>>::value == 2? 0: 1;
}

View File

@@ -0,0 +1,17 @@
# Copyright 2018 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
cmake_minimum_required(VERSION 3.5...3.16)
project(cmake_subdir_test LANGUAGES CXX)
add_subdirectory(../.. boostorg/mp11)
add_executable(main main.cpp)
target_link_libraries(main Boost::mp11)
enable_testing()
add_test(NAME main COMMAND main)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)

View File

@@ -0,0 +1,12 @@
// Copyright 2018 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
#include <boost/mp11.hpp>
using namespace boost::mp11;
int main()
{
using L1 = mp_list<int, float, int, float>;
return mp_size<mp_unique<L1>>::value == 2? 0: 1;
}

View File

@@ -0,0 +1,222 @@
// Copyright 2015, 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
#if defined(_MSC_VER)
#pragma warning( disable: 4244 ) // 'initializing': conversion from 'int' to 'char', possible loss of data
#endif
#include <boost/mp11/tuple.hpp>
#include <boost/mp11/detail/config.hpp>
#include <boost/core/lightweight_test.hpp>
#include <tuple>
#include <memory>
#include <utility>
#include <array>
struct T1
{
int x, y, z;
T1( int x = 0, int y = 0, int z = 0 ): x(x), y(y), z(z) {}
};
struct T2
{
std::unique_ptr<int> x, y, z;
T2( std::unique_ptr<int> x, std::unique_ptr<int> y, std::unique_ptr<int> z ): x(std::move(x)), y(std::move(y)), z(std::move(z)) {}
#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 )
T2( T2&& r ): x( std::move(r.x) ), y( std::move(r.y) ), z( std::move(r.z) ) {}
#endif
};
int main()
{
using boost::mp11::construct_from_tuple;
{
std::tuple<int, short, char> tp{ 1, 2, 3 };
{
T1 t1 = construct_from_tuple<T1>( tp );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 3 );
}
{
T1 t1 = construct_from_tuple<T1>( std::move(tp) );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 3 );
}
}
{
std::tuple<int, short, char> const tp{ 1, 2, 3 };
{
T1 t1 = construct_from_tuple<T1>( tp );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 3 );
}
{
T1 t1 = construct_from_tuple<T1>( std::move(tp) );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 3 );
}
}
#if defined( __clang_major__ ) && __clang_major__ == 3 && __clang_minor__ < 8
#else
{
std::tuple<std::unique_ptr<int>, std::unique_ptr<int>, std::unique_ptr<int>> tp{ std::unique_ptr<int>(new int(1)), std::unique_ptr<int>(new int(2)), std::unique_ptr<int>(new int(3)) };
T2 t2 = construct_from_tuple<T2>( std::move(tp) );
BOOST_TEST_EQ( *t2.x, 1 );
BOOST_TEST_EQ( *t2.y, 2 );
BOOST_TEST_EQ( *t2.z, 3 );
}
#endif
{
std::pair<int, short> tp{ 1, 2 };
{
T1 t1 = construct_from_tuple<T1>( tp );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 0 );
}
{
T1 t1 = construct_from_tuple<T1>( std::move(tp) );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 0 );
}
}
{
std::pair<int, short> const tp{ 1, 2 };
{
T1 t1 = construct_from_tuple<T1>( tp );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 0 );
}
{
T1 t1 = construct_from_tuple<T1>( std::move(tp) );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 0 );
}
}
{
std::array<int, 3> tp{{ 1, 2, 3 }};
{
T1 t1 = construct_from_tuple<T1>( tp );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 3 );
}
{
T1 t1 = construct_from_tuple<T1>( std::move(tp) );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 3 );
}
}
{
std::array<int, 3> const tp{{ 1, 2, 3 }};
{
T1 t1 = construct_from_tuple<T1>( tp );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 3 );
}
{
T1 t1 = construct_from_tuple<T1>( std::move(tp) );
BOOST_TEST_EQ( t1.x, 1 );
BOOST_TEST_EQ( t1.y, 2 );
BOOST_TEST_EQ( t1.z, 3 );
}
}
{
std::tuple<> tp;
{
T1 t1 = construct_from_tuple<T1>( tp );
BOOST_TEST_EQ( t1.x, 0 );
BOOST_TEST_EQ( t1.y, 0 );
BOOST_TEST_EQ( t1.z, 0 );
}
{
T1 t1 = construct_from_tuple<T1>( std::move(tp) );
BOOST_TEST_EQ( t1.x, 0 );
BOOST_TEST_EQ( t1.y, 0 );
BOOST_TEST_EQ( t1.z, 0 );
}
}
{
std::array<int, 0> tp;
{
T1 t1 = construct_from_tuple<T1>( tp );
BOOST_TEST_EQ( t1.x, 0 );
BOOST_TEST_EQ( t1.y, 0 );
BOOST_TEST_EQ( t1.z, 0 );
}
{
T1 t1 = construct_from_tuple<T1>( std::move(tp) );
BOOST_TEST_EQ( t1.x, 0 );
BOOST_TEST_EQ( t1.y, 0 );
BOOST_TEST_EQ( t1.z, 0 );
}
}
return boost::report_errors();
}

View File

@@ -0,0 +1,87 @@
// Copyright 2015 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
#if defined(_MSC_VER)
#pragma warning( disable: 4244 ) // 'initializing': conversion from 'int' to 'char', possible loss of data
#endif
#include <boost/mp11/tuple.hpp>
#include <boost/mp11/detail/config.hpp>
// Technically std::tuple isn't constexpr enabled in C++11, but it works with libstdc++
#if defined( BOOST_MP11_NO_CONSTEXPR ) || ( !defined(_MSC_VER) && !defined( __GLIBCXX__ ) && __cplusplus < 201400L )
int main() {}
#else
#include <tuple>
#include <array>
#include <utility>
struct T1
{
int x, y, z;
constexpr T1( int x = 0, int y = 0, int z = 0 ): x(x), y(y), z(z) {}
};
int main()
{
using boost::mp11::construct_from_tuple;
{
constexpr std::tuple<int, short, char> tp{ 1, 2, 3 };
constexpr auto r = construct_from_tuple<T1>( tp );
static_assert( r.x == 1, "r.x == 1" );
static_assert( r.y == 2, "r.y == 2" );
static_assert( r.z == 3, "r.z == 3" );
}
{
constexpr std::pair<short, char> tp{ 1, 2 };
constexpr auto r = construct_from_tuple<T1>( tp );
static_assert( r.x == 1, "r.x == 1" );
static_assert( r.y == 2, "r.y == 2" );
static_assert( r.z == 0, "r.z == 0" );
}
{
constexpr std::array<short, 3> tp{{ 1, 2, 3 }};
constexpr auto r = construct_from_tuple<T1>( tp );
static_assert( r.x == 1, "r.x == 1" );
static_assert( r.y == 2, "r.y == 2" );
static_assert( r.z == 3, "r.z == 3" );
}
#if defined( __clang_major__ ) && __clang_major__ == 3 && __clang_minor__ < 9
// "error: default initialization of an object of const type 'const std::tuple<>' without a user-provided default constructor"
#else
{
constexpr std::tuple<> tp;
constexpr auto r = construct_from_tuple<T1>( tp );
static_assert( r.x == 0, "r.x == 0" );
static_assert( r.y == 0, "r.y == 0" );
static_assert( r.z == 0, "r.z == 0" );
}
#endif
}
#endif

View File

@@ -0,0 +1,17 @@
// Copyright 2019 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
#include <boost/mp11/function.hpp>
#include <boost/version.hpp>
#include <boost/core/lightweight_test.hpp>
int main()
{
BOOST_TEST_EQ( BOOST_MP11_VERSION, BOOST_VERSION );
return boost::report_errors();
}

View File

@@ -0,0 +1,59 @@
// Copyright 2015 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
#include <boost/mp11/integer_sequence.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
int main()
{
using boost::mp11::integer_sequence;
using boost::mp11::make_integer_sequence;
using boost::mp11::index_sequence;
using boost::mp11::make_index_sequence;
using boost::mp11::index_sequence_for;
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<int, 0>, integer_sequence<int>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<int, 1>, integer_sequence<int, 0>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<int, 2>, integer_sequence<int, 0, 1>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<int, 3>, integer_sequence<int, 0, 1, 2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<int, 4>, integer_sequence<int, 0, 1, 2, 3>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<char, 0>, integer_sequence<char>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<char, 1>, integer_sequence<char, 0>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<char, 2>, integer_sequence<char, 0, 1>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<char, 3>, integer_sequence<char, 0, 1, 2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<char, 4>, integer_sequence<char, 0, 1, 2, 3>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<std::size_t, 0>, integer_sequence<std::size_t>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<std::size_t, 1>, integer_sequence<std::size_t, 0>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<std::size_t, 2>, integer_sequence<std::size_t, 0, 1>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<std::size_t, 3>, integer_sequence<std::size_t, 0, 1, 2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_integer_sequence<std::size_t, 4>, integer_sequence<std::size_t, 0, 1, 2, 3>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_index_sequence<0>, integer_sequence<std::size_t>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_index_sequence<1>, integer_sequence<std::size_t, 0>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_index_sequence<2>, integer_sequence<std::size_t, 0, 1>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_index_sequence<3>, integer_sequence<std::size_t, 0, 1, 2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_index_sequence<4>, integer_sequence<std::size_t, 0, 1, 2, 3>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_index_sequence<0>, index_sequence<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_index_sequence<1>, index_sequence<0>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_index_sequence<2>, index_sequence<0, 1>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_index_sequence<3>, index_sequence<0, 1, 2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<make_index_sequence<4>, index_sequence<0, 1, 2, 3>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<index_sequence_for<>, index_sequence<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<index_sequence_for<void>, index_sequence<0>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<index_sequence_for<void, void>, index_sequence<0, 1>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<index_sequence_for<void, void, void>, index_sequence<0, 1, 2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<index_sequence_for<void, void, void, void>, index_sequence<0, 1, 2, 3>>));
return boost::report_errors();
}

View File

@@ -0,0 +1,17 @@
// Copyright 2019 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
#include <boost/mp11/integer_sequence.hpp>
#include <boost/version.hpp>
#include <boost/core/lightweight_test.hpp>
int main()
{
BOOST_TEST_EQ( BOOST_MP11_VERSION, BOOST_VERSION );
return boost::report_errors();
}

View File

@@ -0,0 +1,70 @@
// Copyright 2015 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
#include <boost/mp11/integral.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <cstddef>
int main()
{
using boost::mp11::mp_bool;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_bool<false>, std::integral_constant<bool, false>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_bool<true>, std::integral_constant<bool, true>>));
using boost::mp11::mp_true;
using boost::mp11::mp_false;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_false, std::integral_constant<bool, false>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_true, std::integral_constant<bool, true>>));
using boost::mp11::mp_int;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_int<0>, std::integral_constant<int, 0>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_int<814>, std::integral_constant<int, 814>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_int<-144>, std::integral_constant<int, -144>>));
using boost::mp11::mp_size_t;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_size_t<0>, std::integral_constant<std::size_t, 0>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_size_t<1972>, std::integral_constant<std::size_t, 1972>>));
using boost::mp11::mp_to_bool;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_to_bool<mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_to_bool<mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_to_bool<mp_int<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_to_bool<mp_int<1>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_to_bool<mp_int<107>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_to_bool<mp_int<-1>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_to_bool<mp_int<-91>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_to_bool<mp_size_t<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_to_bool<mp_size_t<1>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_to_bool<mp_size_t<442>>, mp_true>));
using boost::mp11::mp_not;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_not<mp_false>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_not<mp_true>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_not<mp_int<0>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_not<mp_int<1>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_not<mp_int<107>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_not<mp_int<-1>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_not<mp_int<-91>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_not<mp_size_t<0>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_not<mp_size_t<1>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_not<mp_size_t<442>>, mp_false>));
return boost::report_errors();
}

View File

@@ -0,0 +1,17 @@
// Copyright 2019 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
#include <boost/mp11/integral.hpp>
#include <boost/version.hpp>
#include <boost/core/lightweight_test.hpp>
int main()
{
BOOST_TEST_EQ( BOOST_MP11_VERSION, BOOST_VERSION );
return boost::report_errors();
}

View File

@@ -0,0 +1,17 @@
// Copyright 2019 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
#include <boost/mp11/list.hpp>
#include <boost/version.hpp>
#include <boost/core/lightweight_test.hpp>
int main()
{
BOOST_TEST_EQ( BOOST_MP11_VERSION, BOOST_VERSION );
return boost::report_errors();
}

View File

@@ -0,0 +1,17 @@
// Copyright 2019 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
#include <boost/mp11/map.hpp>
#include <boost/version.hpp>
#include <boost/core/lightweight_test.hpp>
int main()
{
BOOST_TEST_EQ( BOOST_MP11_VERSION, BOOST_VERSION );
return boost::report_errors();
}

View File

@@ -0,0 +1,14 @@
// Copyright 2015 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
#include <boost/mp11.hpp>
int main()
{
}

View File

@@ -0,0 +1,17 @@
// Copyright 2019 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
#include <boost/mp11.hpp>
#include <boost/version.hpp>
#include <boost/core/lightweight_test.hpp>
int main()
{
BOOST_TEST_EQ( BOOST_MP11_VERSION, BOOST_VERSION );
return boost::report_errors();
}

View File

@@ -0,0 +1,70 @@
// Copyright 2015, 2016 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
#include <boost/mp11/function.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/detail/config.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
using boost::mp11::mp_all;
template<class V, class... T> using check1 = mp_all<std::is_same<V, void>, std::is_copy_constructible<T>..., std::is_copy_assignable<T>...>;
template<class V, class... T> using check2 = mp_all<std::is_same<V, void>, mp_all<std::is_copy_constructible<T>..., mp_all<std::is_copy_assignable<T>...>>>;
int main()
{
using boost::mp11::mp_true;
using boost::mp11::mp_false;
using boost::mp11::mp_int;
using boost::mp11::mp_size_t;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_int<-7>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_int<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_size_t<7>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_size_t<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_true, mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_false, mp_true>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_true, mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_false, mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_int<-7>, mp_int<7>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_size_t<(size_t)-1>, mp_size_t<1>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_true, mp_true, mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_true, mp_false, mp_true>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_false, mp_false, mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_true, mp_true, mp_true, mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_true, mp_false, mp_true, mp_true>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_false, mp_false, mp_false, mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_int<1>, mp_int<2>, mp_int<-11>, mp_int<14>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_int<1>, mp_int<0>, mp_int<-11>, mp_int<14>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_size_t<1>, mp_size_t<2>, mp_size_t<114>, mp_size_t<8>, mp_size_t<94>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all<mp_size_t<1>, mp_size_t<2>, mp_size_t<114>, mp_size_t<0>, mp_size_t<94>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<check1<void, int, float>, mp_true>));
#if !BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 40900 )
BOOST_TEST_TRAIT_TRUE((std::is_same<check2<void, int, float>, mp_true>));
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,42 @@
// Copyright 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/mp11/detail/config.hpp>
#if BOOST_MP11_MSVC
# pragma warning( disable: 4503 ) // decorated name length exceeded
#endif
#include <boost/mp11/function.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
int main()
{
using boost::mp11::mp_all;
using boost::mp11::mp_list;
using boost::mp11::mp_apply;
using boost::mp11::mp_true;
using boost::mp11::mp_false;
using boost::mp11::mp_repeat_c;
using boost::mp11::mp_push_back;
int const N = 1089;
using L1 = mp_repeat_c<mp_list<mp_true>, N>;
using R1 = mp_apply<mp_all, L1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<R1, mp_true>));
using L2 = mp_push_back<L1, mp_false>;
using R2 = mp_apply<mp_all, L2>;
BOOST_TEST_TRAIT_TRUE((std::is_same<R2, mp_false>));
return boost::report_errors();
}

View File

@@ -0,0 +1,80 @@
// Copyright 2015, 2016 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
#include <boost/mp11/detail/config.hpp>
#if BOOST_MP11_MSVC
# pragma warning( disable: 4503 ) // decorated name length exceeded
#endif
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <tuple>
#include <utility>
struct X1 {};
int main()
{
using boost::mp11::mp_list;
using boost::mp11::mp_all_of;
using boost::mp11::mp_true;
using boost::mp11::mp_false;
{
using L1 = mp_list<>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of<L1, std::is_const>, mp_true>));
using L2 = mp_list<X1 const, X1 const, X1 const volatile, X1 const, X1 const volatile>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of<L2, std::is_volatile>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of<L2, std::is_const>, mp_true>));
}
{
using L1 = std::tuple<>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of<L1, std::is_const>, mp_true>));
using L2 = std::tuple<X1 const, X1 const, X1 const volatile, X1 const, X1 const volatile>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of<L2, std::is_volatile>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of<L2, std::is_const>, mp_true>));
}
{
using L2 = std::pair<X1 const, X1 const volatile>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of<L2, std::is_volatile>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of<L2, std::is_const>, mp_true>));
}
{
using boost::mp11::mp_repeat_c;
using boost::mp11::mp_to_bool;
using boost::mp11::mp_push_back;
int const N = 1089;
using L1 = mp_repeat_c<mp_list<mp_true>, N>;
using R1 = mp_all_of<L1, mp_to_bool>;
BOOST_TEST_TRAIT_TRUE((std::is_same<R1, mp_true>));
using L2 = mp_push_back<L1, mp_false>;
using R2 = mp_all_of<L2, mp_to_bool>;
BOOST_TEST_TRAIT_TRUE((std::is_same<R2, mp_false>));
}
return boost::report_errors();
}

View File

@@ -0,0 +1,59 @@
// Copyright 2015, 2016, 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
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <tuple>
#include <utility>
struct X1 {};
int main()
{
using boost::mp11::mp_list;
using boost::mp11::mp_all_of_q;
using boost::mp11::mp_true;
using boost::mp11::mp_false;
using boost::mp11::mp_quote;
{
using L1 = mp_list<>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of_q<L1, mp_quote<std::is_const>>, mp_true>));
using L2 = mp_list<X1 const, X1 const, X1 const volatile, X1 const, X1 const volatile>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of_q<L2, mp_quote<std::is_volatile>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of_q<L2, mp_quote<std::is_const>>, mp_true>));
}
{
using L1 = std::tuple<>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of_q<L1, mp_quote<std::is_const>>, mp_true>));
using L2 = std::tuple<X1 const, X1 const, X1 const volatile, X1 const, X1 const volatile>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of_q<L2, mp_quote<std::is_volatile>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of_q<L2, mp_quote<std::is_const>>, mp_true>));
}
{
using L2 = std::pair<X1 const, X1 const volatile>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of_q<L2, mp_quote<std::is_volatile>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_all_of_q<L2, mp_quote<std::is_const>>, mp_true>));
}
return boost::report_errors();
}

View File

@@ -0,0 +1,64 @@
// Copyright 2015-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
#include <boost/mp11/function.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
int main()
{
using boost::mp11::mp_and;
using boost::mp11::mp_true;
using boost::mp11::mp_false;
using boost::mp11::mp_int;
using boost::mp11::mp_size_t;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_int<-7>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_int<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_size_t<7>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_size_t<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_true, mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_true, mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_false, void>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_int<-4>, mp_int<5>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_int<-4>, mp_int<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_int<0>, void>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_size_t<7>, mp_size_t<8>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_size_t<7>, mp_size_t<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_size_t<0>, void>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_true, mp_true, mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_true, mp_true, mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_true, mp_false, void>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_false, void, void>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_true, mp_true, mp_true, mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_true, mp_true, mp_true, mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_true, mp_true, mp_false, void>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_true, mp_false, void, void>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_false, void, void, void>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_int<1>, mp_int<2>, mp_int<-11>, mp_int<14>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_int<1>, mp_int<0>, void, void>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_size_t<1>, mp_size_t<2>, mp_size_t<114>, mp_size_t<8>, mp_size_t<94>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_and<mp_size_t<1>, mp_size_t<2>, mp_size_t<0>, void, void>, mp_false>));
return boost::report_errors();
}

View File

@@ -0,0 +1,91 @@
// Copyright 2015, 2016, 2019 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
#include <boost/mp11/function.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/set.hpp>
#include <boost/mp11/detail/config.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
using boost::mp11::mp_any;
using boost::mp11::mp_all;
template<class... T> using check1 = mp_any<std::is_nothrow_copy_constructible<T>..., mp_any<std::is_nothrow_move_constructible<T>...>>;
template<class... T> using check2 = mp_any<mp_any<std::is_nothrow_copy_constructible<T>...>, std::is_nothrow_move_constructible<T>...>;
template<class... T> using check3 = mp_any<mp_all<std::is_nothrow_copy_constructible<T>...>, std::is_nothrow_default_constructible<T>...>;
template<bool is_trivially_destructible, bool is_single_buffered, class... T> struct variant_base_impl {};
#if BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 40800 )
template<class... T> using variant_base = variant_base_impl<mp_all<std::has_trivial_destructor<T>...>::value, mp_any<mp_all<std::is_nothrow_move_constructible<T>...>, std::is_nothrow_default_constructible<T>...>::value, T...>;
#else
template<class... T> using variant_base = variant_base_impl<mp_all<std::is_trivially_destructible<T>...>::value, mp_any<mp_all<std::is_nothrow_move_constructible<T>...>, std::is_nothrow_default_constructible<T>...>::value, T...>;
#endif
using boost::mp11::mp_set_contains;
template<class T, class... S> using in_any_set = mp_any< mp_set_contains<S, T>... >;
int main()
{
using boost::mp11::mp_true;
using boost::mp11::mp_false;
using boost::mp11::mp_int;
using boost::mp11::mp_size_t;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_int<-7>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_int<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_size_t<7>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_size_t<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_true, mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_false, mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_true, mp_false>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_false, mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_int<-7>, mp_int<7>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_size_t<(size_t)-1>, mp_size_t<1>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_true, mp_true, mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_false, mp_false, mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_false, mp_false, mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_true, mp_true, mp_true, mp_true>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_false, mp_false, mp_true, mp_false>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_false, mp_false, mp_false, mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_int<1>, mp_int<2>, mp_int<-11>, mp_int<14>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_int<0>, mp_int<0>, mp_int<-11>, mp_int<0>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_int<0>, mp_int<0>, mp_int<0>, mp_int<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_size_t<1>, mp_size_t<2>, mp_size_t<114>, mp_size_t<8>, mp_size_t<94>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_size_t<0>, mp_size_t<0>, mp_size_t<114>, mp_size_t<0>, mp_size_t<0>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_size_t<0>, mp_size_t<0>, mp_size_t<0>, mp_size_t<0>, mp_size_t<0>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_size_t<0>, mp_int<0>, mp_false, mp_size_t<141>>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any<mp_size_t<0>, mp_int<0>, mp_false>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<check1<void, int, float>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<check2<void, int, float>, mp_true>));
BOOST_TEST_TRAIT_TRUE((std::is_same<check3<void, int, float>, mp_true>));
variant_base<void, int, float>();
using boost::mp11::mp_list;
BOOST_TEST_TRAIT_TRUE((std::is_same<in_any_set<void, mp_list<void>, mp_list<int>>, mp_true>));
return boost::report_errors();
}

View File

@@ -0,0 +1,42 @@
// Copyright 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/mp11/detail/config.hpp>
#if BOOST_MP11_MSVC
# pragma warning( disable: 4503 ) // decorated name length exceeded
#endif
#include <boost/mp11/function.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
int main()
{
using boost::mp11::mp_any;
using boost::mp11::mp_list;
using boost::mp11::mp_apply;
using boost::mp11::mp_true;
using boost::mp11::mp_false;
using boost::mp11::mp_repeat_c;
using boost::mp11::mp_push_back;
int const N = 1089;
using L1 = mp_repeat_c<mp_list<mp_false>, N>;
using R1 = mp_apply<mp_any, L1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<R1, mp_false>));
using L2 = mp_push_back<L1, mp_true>;
using R2 = mp_apply<mp_any, L2>;
BOOST_TEST_TRAIT_TRUE((std::is_same<R2, mp_true>));
return boost::report_errors();
}

View File

@@ -0,0 +1,95 @@
// Copyright 2015, 2016 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
#include <boost/mp11/detail/config.hpp>
#if BOOST_MP11_MSVC
# pragma warning( disable: 4503 ) // decorated name length exceeded
#endif
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <tuple>
#include <utility>
struct X1 {};
int main()
{
using boost::mp11::mp_list;
using boost::mp11::mp_any_of;
using boost::mp11::mp_true;
using boost::mp11::mp_false;
{
using L1 = mp_list<>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L1, std::is_const>, mp_false>));
using L2 = mp_list<X1, X1 const, X1, X1, X1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L2, std::is_volatile>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L2, std::is_const>, mp_true>));
using L3 = mp_list<X1 const, X1 const, X1, X1 const, X1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L3, std::is_volatile>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L3, std::is_const>, mp_true>));
}
{
using L1 = std::tuple<>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L1, std::is_const>, mp_false>));
using L2 = std::tuple<X1, X1 const, X1, X1, X1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L2, std::is_volatile>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L2, std::is_const>, mp_true>));
using L3 = std::tuple<X1 const, X1 const, X1, X1 const, X1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L3, std::is_volatile>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L3, std::is_const>, mp_true>));
}
{
using L2 = std::pair<X1 const, X1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L2, std::is_volatile>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L2, std::is_const>, mp_true>));
using L3 = std::pair<X1 const, X1 const>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L3, std::is_volatile>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of<L3, std::is_const>, mp_true>));
}
{
using boost::mp11::mp_repeat_c;
using boost::mp11::mp_to_bool;
using boost::mp11::mp_push_back;
int const N = 1089;
using L1 = mp_repeat_c<mp_list<mp_false>, N>;
using R1 = mp_any_of<L1, mp_to_bool>;
BOOST_TEST_TRAIT_TRUE((std::is_same<R1, mp_false>));
using L2 = mp_push_back<L1, mp_true>;
using R2 = mp_any_of<L2, mp_to_bool>;
BOOST_TEST_TRAIT_TRUE((std::is_same<R2, mp_true>));
}
return boost::report_errors();
}

View File

@@ -0,0 +1,74 @@
// Copyright 2015, 2016, 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
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <tuple>
#include <utility>
struct X1 {};
int main()
{
using boost::mp11::mp_list;
using boost::mp11::mp_any_of_q;
using boost::mp11::mp_true;
using boost::mp11::mp_false;
using boost::mp11::mp_quote;
{
using L1 = mp_list<>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L1, mp_quote<std::is_const>>, mp_false>));
using L2 = mp_list<X1, X1 const, X1, X1, X1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L2, mp_quote<std::is_volatile>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L2, mp_quote<std::is_const>>, mp_true>));
using L3 = mp_list<X1 const, X1 const, X1, X1 const, X1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L3, mp_quote<std::is_volatile>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L3, mp_quote<std::is_const>>, mp_true>));
}
{
using L1 = std::tuple<>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L1, mp_quote<std::is_const>>, mp_false>));
using L2 = std::tuple<X1, X1 const, X1, X1, X1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L2, mp_quote<std::is_volatile>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L2, mp_quote<std::is_const>>, mp_true>));
using L3 = std::tuple<X1 const, X1 const, X1, X1 const, X1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L3, mp_quote<std::is_volatile>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L3, mp_quote<std::is_const>>, mp_true>));
}
{
using L2 = std::pair<X1 const, X1>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L2, mp_quote<std::is_volatile>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L2, mp_quote<std::is_const>>, mp_true>));
using L3 = std::pair<X1 const, X1 const>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L3, mp_quote<std::is_volatile>>, mp_false>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_any_of_q<L3, mp_quote<std::is_const>>, mp_true>));
}
return boost::report_errors();
}

View File

@@ -0,0 +1,76 @@
// Copyright 2015 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
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/mp11/list.hpp>
#include <type_traits>
#include <tuple>
#include <utility>
struct X1 {};
struct X2 {};
struct X3 {};
struct X4 {};
struct X5 {};
struct X6 {};
int main()
{
using boost::mp11::mp_list;
using boost::mp11::mp_append;
using L1 = mp_list<char[1], char[1]>;
using L2 = mp_list<char[2], char[2]>;
using L3 = mp_list<char[3], char[3]>;
using L4 = mp_list<char[4], char[4]>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<>, mp_list<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<L1>, mp_list<char[1], char[1]>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<L1, L2>, mp_list<char[1], char[1], char[2], char[2]>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<L1, L2, L3>, mp_list<char[1], char[1], char[2], char[2], char[3], char[3]>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<L1, L2, L3, L4>, mp_list<char[1], char[1], char[2], char[2], char[3], char[3], char[4], char[4]>>));
//
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>>, std::tuple<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, std::tuple<X1>>, std::tuple<X1>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, std::tuple<X1>, std::tuple<X2>>, std::tuple<X1, X2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, std::tuple<X1>, std::tuple<X2>, std::tuple<X3>>, std::tuple<X1, X2, X3>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, std::tuple<X1>, std::tuple<X2>, std::tuple<X3>, std::tuple<X4>>, std::tuple<X1, X2, X3, X4>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, std::tuple<X1>, std::tuple<X2>, std::tuple<X3>, std::tuple<X4>, std::tuple<X5>>, std::tuple<X1, X2, X3, X4, X5>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, std::tuple<X1>, std::tuple<X2>, std::tuple<X3>, std::tuple<X4>, std::tuple<X5>, std::tuple<X6>>, std::tuple<X1, X2, X3, X4, X5, X6>>));
//
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, mp_list<>>, std::tuple<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, mp_list<X1>>, std::tuple<X1>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, mp_list<X1>, std::tuple<X2>>, std::tuple<X1, X2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, mp_list<X1>, std::tuple<X2>, mp_list<X3>>, std::tuple<X1, X2, X3>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, mp_list<X1>, std::tuple<X2>, mp_list<X3>, std::tuple<X4>>, std::tuple<X1, X2, X3, X4>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, mp_list<X1>, std::tuple<X2>, mp_list<X3>, std::tuple<X4>, mp_list<X5>>, std::tuple<X1, X2, X3, X4, X5>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, mp_list<X1>, std::tuple<X2>, mp_list<X3>, std::tuple<X4>, mp_list<X5>, std::tuple<X6>>, std::tuple<X1, X2, X3, X4, X5, X6>>));
//
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, std::pair<X1, X2>>, std::tuple<X1, X2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, std::pair<X1, X2>, std::pair<X3, X4>>, std::tuple<X1, X2, X3, X4>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::tuple<>, std::pair<X1, X2>, std::pair<X3, X4>, std::pair<X5, X6>>, std::tuple<X1, X2, X3, X4, X5, X6>>));
//
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::pair<X1, X2>>, std::pair<X1, X2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::pair<X1, X2>, mp_list<>>, std::pair<X1, X2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::pair<X1, X2>, mp_list<>, mp_list<>>, std::pair<X1, X2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::pair<X1, X2>, mp_list<>, mp_list<>, mp_list<>>, std::pair<X1, X2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_append<std::pair<X1, X2>, mp_list<>, mp_list<>, mp_list<>, mp_list<>>, std::pair<X1, X2>>));
//
return boost::report_errors();
}

View File

@@ -0,0 +1,38 @@
// Copyright 2015-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
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/algorithm.hpp>
#include <type_traits>
#include <tuple>
#include <utility>
template<class T> struct W;
int main()
{
using boost::mp11::mp_list;
using boost::mp11::mp_append;
using boost::mp11::mp_iota_c;
using boost::mp11::mp_transform;
using boost::mp11::mp_rename;
using boost::mp11::mp_push_front;
using L1 = mp_iota_c<125>;
using L2 = mp_transform<W, L1>;
using L3 = mp_push_front<L2, mp_list<>>;
using L4 = mp_rename<L3, mp_append>;
BOOST_TEST_TRAIT_TRUE((std::is_same<L4, L1>));
//
return boost::report_errors();
}

View File

@@ -0,0 +1,32 @@
// Copyright 2019 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
#include <boost/mp11/list.hpp>
#include <boost/mp11/utility.hpp>
#include <boost/core/lightweight_test_trait.hpp>
int main()
{
using boost::mp11::mp_append;
using boost::mp11::mp_valid;
using boost::mp11::mp_list;
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_append, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_append, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_append, void, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_append, void, void, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_append, void, void, void, void, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_append, mp_list<>, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_append, mp_list<>, mp_list<>, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_append, mp_list<>, mp_list<>, mp_list<>, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<mp_append, mp_list<>, mp_list<>, mp_list<>, mp_list<>, void>));
return boost::report_errors();
}

View File

@@ -0,0 +1,113 @@
// Copyright 2015-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
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/utility.hpp>
#include <type_traits>
#include <tuple>
#include <utility>
template<class... T> struct X {};
template<class... T> using Y = X<T...>;
struct Q
{
template<class... T> using fn = X<T...>;
};
int main()
{
using boost::mp11::mp_list;
using boost::mp11::mp_quote;
using boost::mp11::mp_apply_q;
using L1 = mp_list<>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<mp_list>, L1>, mp_list<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::tuple>, L1>, std::tuple<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<X>, L1>, X<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<Y>, L1>, Y<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<Q, L1>, X<>>));
using L2 = mp_list<char>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<mp_list>, L2>, mp_list<char>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::tuple>, L2>, std::tuple<char>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<X>, L2>, X<char>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<Y>, L2>, Y<char>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<Q, L2>, X<char>>));
using L3 = mp_list<char, double>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<mp_list>, L3>, mp_list<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::tuple>, L3>, std::tuple<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<X>, L3>, X<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<Y>, L3>, Y<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::pair>, L3>, std::pair<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<Q, L3>, X<char, double>>));
using L4 = mp_list<int, char, float>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<mp_list>, L4>, mp_list<int, char, float>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::tuple>, L4>, std::tuple<int, char, float>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<X>, L4>, X<int, char, float>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<Y>, L4>, Y<int, char, float>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<Q, L4>, X<int, char, float>>));
//
using L5 = std::tuple<>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<mp_list>, L5>, mp_list<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::tuple>, L5>, std::tuple<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<X>, L5>, X<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<Y>, L5>, Y<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<Q, L5>, X<>>));
using L6 = std::tuple<char>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<mp_list>, L6>, mp_list<char>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::tuple>, L6>, std::tuple<char>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<X>, L6>, X<char>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<Y>, L6>, Y<char>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<Q, L6>, X<char>>));
using L7 = std::tuple<char, double>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<mp_list>, L7>, mp_list<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::tuple>, L7>, std::tuple<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<X>, L7>, X<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<Y>, L7>, Y<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::pair>, L7>, std::pair<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<Q, L7>, X<char, double>>));
using L8 = std::tuple<int, char, float>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<mp_list>, L8>, mp_list<int, char, float>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::tuple>, L8>, std::tuple<int, char, float>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<X>, L8>, X<int, char, float>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<Y>, L8>, Y<int, char, float>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<Q, L8>, X<int, char, float>>));
//
using L9 = std::pair<char, double>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<mp_list>, L9>, mp_list<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::tuple>, L9>, std::tuple<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<X>, L9>, X<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<Y>, L9>, Y<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<mp_quote<std::pair>, L9>, std::pair<char, double>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_apply_q<Q, L9>, X<char, double>>));
//
return boost::report_errors();
}

View File

@@ -0,0 +1,64 @@
// Copyright 2015, 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
#include <boost/mp11/list.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <tuple>
#include <utility>
struct X1 {};
struct X2 {};
struct X3 {};
int main()
{
using boost::mp11::mp_list;
using boost::mp11::mp_assign;
using L1 = mp_list<int, void(), float[]>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L1, mp_list<>>, mp_list<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L1, mp_list<X1>>, mp_list<X1>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L1, mp_list<X1, X2>>, mp_list<X1, X2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L1, mp_list<X1, X2, X3>>, mp_list<X1, X2, X3>>));
//
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L1, std::tuple<>>, mp_list<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L1, std::tuple<X1>>, mp_list<X1>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L1, std::tuple<X1, X2>>, mp_list<X1, X2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L1, std::tuple<X1, X2, X3>>, mp_list<X1, X2, X3>>));
//
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L1, std::pair<X1, X2>>, mp_list<X1, X2>>));
//
using L2 = std::tuple<int, char, float>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L2, mp_list<>>, std::tuple<>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L2, mp_list<X1>>, std::tuple<X1>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L2, mp_list<X1, X2>>, std::tuple<X1, X2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L2, mp_list<X1, X2, X3>>, std::tuple<X1, X2, X3>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L2, std::pair<X1, X2>>, std::tuple<X1, X2>>));
//
using L3 = std::pair<int, char>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L3, mp_list<X1, X2>>, std::pair<X1, X2>>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_assign<L3, std::pair<X1, X2>>, std::pair<X1, X2>>));
//
return boost::report_errors();
}

View File

@@ -0,0 +1,74 @@
// Copyright 2015 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
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/integral.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <tuple>
#include <utility>
struct X1 {};
struct X2 {};
struct X3 {};
struct X4 {};
struct X5 {};
int main()
{
using boost::mp11::mp_list;
using boost::mp11::mp_at;
using boost::mp11::mp_at_c;
using boost::mp11::mp_size_t;
{
using L1 = mp_list<X1, X2, X3, X4, X5>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 0>, X1>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 1>, X2>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 2>, X3>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 3>, X4>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 4>, X5>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<0>>, X1>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<1>>, X2>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<2>>, X3>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<3>>, X4>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<4>>, X5>));
}
{
using L1 = std::tuple<X1, X2, X3, X4, X5>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 0>, X1>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 1>, X2>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 2>, X3>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 3>, X4>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 4>, X5>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<0>>, X1>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<1>>, X2>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<2>>, X3>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<3>>, X4>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<4>>, X5>));
}
{
using L1 = std::pair<X1, X2>;
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 0>, X1>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at_c<L1, 1>, X2>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<0>>, X1>));
BOOST_TEST_TRAIT_TRUE((std::is_same<mp_at<L1, mp_size_t<1>>, X2>));
}
return boost::report_errors();
}

Some files were not shown because too many files have changed in this diff Show More