Compare commits

...

61 Commits

Author SHA1 Message Date
Peter Dimov
a3d35e61fe g++ 4.7 doesn't have std::is_trivially_destructible 2021-01-13 04:51:27 +02:00
Peter Dimov
84a2c175d0 Use variant=release for variant_visit_r under g++/windows 2021-01-13 04:44:56 +02:00
Peter Dimov
ea3268feb4 Add .github/workflows 2021-01-13 04:19:15 +02:00
Peter Dimov
efc1d5acca Add more tests to variant_emplace_index.cpp 2021-01-13 02:32:05 +02:00
Peter Dimov
c6186e0a95 Merge pull request #22 from eldiener/develop
Add "cxxstd" json field. The "cxxstd" json field is being added to ea…
2020-12-16 18:45:01 +02:00
Edward Diener
24ccee2104 Add "cxxstd" json field. The "cxxstd" json field is being added to each Boost library's meta json information for libraries whose minumum C++ standard compilation level is C++11 on up. The value of this field matches one of the values for 'cxxstd' in Boost.Build. The purpose of doing this is to provide information for the Boost website documentation for each library which will specify the minimum C++ standard compilation that an end-user must employ in order to use the particular library. This will aid end-users who want to know if they can successfully use a Boost library based on their C++ compiler's compilation level, without having to search the library's documentation to find this out. 2020-12-16 01:45:24 -05:00
Peter Dimov
93b8618e94 Update maintainer e-mail 2020-12-12 01:08:09 +02:00
Peter Dimov
1ebc29aa02 Remove boost_install call from CMakeLists.txt 2020-06-11 17:21:57 +03:00
Peter Dimov
d3db874762 Document visit<R> 2020-06-03 18:01:57 +03:00
Peter Dimov
5586ebaa64 Add support for visit<R> 2020-06-03 17:00:13 +03:00
Peter Dimov
bede3777a8 Add test for nullary visit 2020-06-03 14:29:24 +03:00
Peter Dimov
b302dd5912 Update changelog 2020-05-22 17:57:29 +03:00
Peter Dimov
2ad6fed07a Update revision history 2020-05-10 19:34:12 +03:00
Peter Dimov
84ea994325 Add specialization for variant_storage_impl<mp_false, ...> 2020-05-09 19:56:27 +03:00
Peter Dimov
465e5bac3d Add specialization for variant_storage_impl<mp_true, ...> to reduce instantiations 2020-05-09 18:14:12 +03:00
Peter Dimov
41829b0fb1 test/variant_many_types: cosmetic fixes 2020-05-09 17:55:42 +03:00
Peter Dimov
b57d75ff80 Merge branch 'develop' into feature/many-types 2020-05-09 14:41:29 +03:00
Peter Dimov
03019860df Fix gcc-10 version check 2020-05-09 05:10:28 +03:00
Peter Dimov
8ec4720d2d Merge branch 'feature/clang-10' into feature/gcc-10 2020-05-09 05:09:11 +03:00
Peter Dimov
75f574fc48 Move warning suppression before the includes 2020-05-09 04:42:27 +03:00
Peter Dimov
1d79adfca0 Add gcc-10 to Travis 2020-05-09 04:32:11 +03:00
Peter Dimov
fa92e40b35 Disable failing constexpr tests on g++ 10.1 2020-05-09 04:31:26 +03:00
Peter Dimov
a403f82691 Disable -Wdeprecated-volatile 2020-05-09 03:57:27 +03:00
Peter Dimov
a7d0da59ad Add clang-10 to Travis 2020-05-09 03:50:20 +03:00
Peter Dimov
fa872cb835 test/variant_many_types: add a constructor to Y 2020-05-08 23:23:19 +03:00
Peter Dimov
93204676f5 Add test/variant_many_types 2020-05-08 22:22:49 +03:00
Peter Dimov
772ef0d312 Support derived types in visit 2020-05-06 20:11:03 +03:00
Peter Dimov
f3b3b533aa Remove local mp_power_set implementation, as it's now in mp11 2020-03-20 02:26:01 +02:00
Peter Dimov
4b60dee4b6 Avoid gcc warning 'base class should be explicitly initialized in copy constructor' 2020-02-01 01:18:40 +02:00
Peter Dimov
76c67c9b21 Use <warnings>extra instead of all 2020-01-31 23:59:00 +02:00
Peter Dimov
308bd731a5 Update documentation 2020-01-23 21:17:49 +02:00
Peter Dimov
719c43316f Disable is_copy_constructible tests on gcc 4.x 2020-01-23 19:13:11 +02:00
Peter Dimov
d6680df4e5 Add a test case to test/variant_copy_construct 2020-01-23 18:33:39 +02:00
Peter Dimov
8cf72527a6 Revert incorrect changes in test/variant_trivial 2020-01-23 18:09:01 +02:00
Peter Dimov
b649a39776 Check std::is_copy_constructible in test/variant_copy_construct 2020-01-23 17:38:03 +02:00
Peter Dimov
37f6efab5d Fix typo 2020-01-23 17:34:36 +02:00
Peter Dimov
5259bdd5fc Disable move triviality tests on libstdc++ 4.x 2020-01-23 17:22:45 +02:00
Peter Dimov
9964e77dd2 Add clang++/trusty to Travis (libstdc++ 4.8) 2020-01-23 15:50:45 +02:00
Peter Dimov
57ab36bd95 Add test/variant_special 2020-01-23 15:24:32 +02:00
Peter Dimov
fac5992e45 Add test/variant_trivial 2020-01-23 03:53:05 +02:00
Peter Dimov
972280e59f Remove commented-out variant_copy_base 2020-01-23 01:08:32 +02:00
Peter Dimov
ef2ef292b9 The msvc-14.0 workarounds are no longer needed 2020-01-22 20:14:11 +02:00
Peter Dimov
3b2fb1a48a Split variant_copy_base into separate cc/ca/mc/ma bases; avoids multiple inheritance, which is a penalty in the MS ABI 2020-01-22 19:59:59 +02:00
Peter Dimov
4f81882bfd Explicitly disable move constructor when needed 2020-01-22 18:30:36 +02:00
Peter Dimov
17bc06b090 Apply msvc-14.0 workarounds 2020-01-22 17:38:45 +02:00
Peter Dimov
c4cad3e96a Use an intermediate trivial base for trivial variants 2020-01-22 17:09:15 +02:00
Peter Dimov
83ff667813 Remove stray compiler: g++ 2020-01-21 02:22:17 +02:00
Peter Dimov
5e76451843 Use BOOST_INCLUDE_LIBRARIES=variant2 in the CMake install test 2020-01-21 00:43:15 +02:00
Peter Dimov
c2b5d101eb Update revision history 2020-01-11 15:22:13 +02:00
Peter Dimov
a92185a86d Add Boost::container_hash to LINK_LIBRARIES 2020-01-11 06:54:23 +02:00
Peter Dimov
a795f9cf01 Add missing inline 2020-01-11 06:41:21 +02:00
Peter Dimov
f6e2e78d7d Libc++ doesn't implement a primary std::hash template under C++11 2020-01-11 06:31:45 +02:00
Peter Dimov
1f05cdfb17 Include <functional>, for g++ trunk (10.0) 2020-01-11 06:06:54 +02:00
Peter Dimov
1203aa97c0 Add g++ 4.8 to Travis 2020-01-11 05:29:07 +02:00
Peter Dimov
b3229d48b7 gcc < 7 doesn't like specializing std::hash in a different namespace 2020-01-11 05:27:57 +02:00
Peter Dimov
be11d94adc Update appveyor.yml 2020-01-11 05:10:28 +02:00
Peter Dimov
fece11142c Add hashing support 2020-01-11 04:51:30 +02:00
Peter Dimov
58b4a21deb Add CMake tests 2020-01-09 17:43:54 +02:00
Peter Dimov
5192a345ab Fix .travis.yml 2019-12-28 22:13:37 +02:00
Peter Dimov
74e6a04a60 Update .travis.yml 2019-12-28 21:35:20 +02:00
Peter Dimov
2af66dd815 Add CMake install support 2019-12-28 18:52:32 +02:00
27 changed files with 1737 additions and 227 deletions

201
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,201 @@
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.7
cxxstd: "03,11"
os: ubuntu-16.04
install: g++-4.7
- toolset: gcc-4.8
cxxstd: "03,11"
os: ubuntu-16.04
install: g++-4.8
- toolset: gcc-4.9
cxxstd: "03,11"
os: ubuntu-16.04
install: g++-4.9
- toolset: gcc-5
cxxstd: "03,11,14,1z"
os: ubuntu-16.04
- toolset: gcc-6
cxxstd: "03,11,14,1z"
os: ubuntu-16.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
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
- toolset: gcc-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
- toolset: clang
compiler: clang++-3.5
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.5
- toolset: clang
compiler: clang++-3.6
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.6
- toolset: clang
compiler: clang++-3.7
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.7
- toolset: clang
compiler: clang++-3.8
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.8
- toolset: clang
compiler: clang++-3.9
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "03,11,14,1z"
os: ubuntu-16.04
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
cxxstd: "03,11,14,17"
os: ubuntu-18.04
- 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,2a"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang
compiler: clang++-10
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:
- 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: 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

View File

@@ -4,9 +4,7 @@
language: cpp
sudo: false
dist: trusty
dist: xenial
branches:
only:
@@ -25,8 +23,14 @@ matrix:
include:
- os: linux
compiler: g++
env: TOOLSET=gcc COMPILER=g++ CXXSTD=11
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
@@ -88,6 +92,17 @@ matrix:
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++-8
env: UBSAN=1 TOOLSET=gcc COMPILER=g++-8 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold
@@ -98,6 +113,11 @@ matrix:
sources:
- ubuntu-toolchain-r-test
- os: linux
dist: trusty
compiler: clang++
env: DIST=trusty TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: linux
compiler: clang++-3.5
env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=11,14,1z
@@ -108,7 +128,6 @@ matrix:
- libstdc++-4.9-dev
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.5
- os: linux
compiler: clang++-3.6
@@ -119,7 +138,6 @@ matrix:
- clang-3.6
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.6
- os: linux
compiler: clang++-3.7
@@ -130,7 +148,6 @@ matrix:
- clang-3.7
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.7
- os: linux
compiler: clang++-3.8
@@ -141,7 +158,6 @@ matrix:
- clang-3.8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.8
- os: linux
compiler: clang++-3.9
@@ -152,7 +168,6 @@ matrix:
- clang-3.9
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.9
- os: linux
compiler: clang++-4.0
@@ -163,7 +178,6 @@ matrix:
- clang-4.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
- os: linux
compiler: clang++-5.0
@@ -174,7 +188,6 @@ matrix:
- clang-5.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-5.0
- os: linux
compiler: clang++-6.0
@@ -185,7 +198,6 @@ matrix:
- clang-6.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-6.0
- os: linux
compiler: clang++-7
@@ -196,7 +208,7 @@ matrix:
- clang-7
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-7
- llvm-toolchain-xenial-7
- os: linux
compiler: clang++-8
@@ -207,20 +219,47 @@ matrix:
- clang-8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-8
- llvm-toolchain-xenial-8
- os: linux
compiler: clang++-6.0
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1
dist: xenial
compiler: clang++-9
env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-6.0
- clang-9
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-6.0
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
dist: xenial
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/xenial/ llvm-toolchain-xenial-10 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
compiler: clang++-8
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1
addons:
apt:
packages:
- clang-8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-8
- os: linux
dist: trusty
compiler: clang++-libc++
env: TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=11,14,1z
addons:
@@ -229,6 +268,7 @@ matrix:
- libc++-dev
- os: linux
dist: trusty
compiler: clang++-libc++
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=11,14,1z UBSAN_OPTIONS=print_stacktrace=1
addons:
@@ -240,22 +280,48 @@ matrix:
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: osx
compiler: clang++
env: UBSAN=1 TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z UBSAN_OPTIONS=print_stacktrace=1
- os: linux
compiler: g++
env: CMAKE_SUBDIR_TEST=1
env: CMAKE_TEST=1
script:
- cd libs/variant2/test/cmake_subdir_test && mkdir __build__ && cd __build__
- mkdir __build__ && cd __build__
- cmake -DBOOST_ENABLE_CMAKE=1 -DBoost_VERBOSE=1 -DBOOST_INCLUDE_LIBRARIES=variant2 ..
- ctest --output-on-failure -R boost_variant2
- os: linux
env: CMAKE_SUBDIR_TEST=1
install:
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
- git clone -b $BOOST_BRANCH https://github.com/boostorg/assert.git ../assert
- git clone -b $BOOST_BRANCH https://github.com/boostorg/config.git ../config
- git clone -b $BOOST_BRANCH https://github.com/boostorg/core.git ../core
- git clone -b $BOOST_BRANCH https://github.com/boostorg/mp11.git ../mp11
script:
- cd test/cmake_subdir_test && mkdir __build__ && cd __build__
- cmake ..
- cmake --build .
- cmake --build . --target check
- os: linux
env: CMAKE_INSTALL_TEST=1
script:
- pip install --user cmake
- mkdir __build__ && cd __build__
- cmake -DBOOST_ENABLE_CMAKE=1 -DBoost_VERBOSE=1 -DBOOST_INCLUDE_LIBRARIES=variant2 -DCMAKE_INSTALL_PREFIX=~/.local ..
- cmake --build . --target install
- cd ../libs/variant2/test/cmake_install_test && mkdir __build__ && cd __build__
- cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
- cmake --build .
- cmake --build . --target check
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/build
- git submodule update --init libs/config
- git submodule update --init tools/boostdep
- mkdir -p libs/variant2
- cp -r $TRAVIS_BUILD_DIR/* libs/variant2

View File

@@ -2,12 +2,9 @@
# Distributed under the Boost Software License, Version 1.0.
# http://www.boost.org/LICENSE_1_0.txt
# Partial (add_subdirectory only) and experimental CMake support
# Subject to change; please do not rely on the contents of this file yet
cmake_minimum_required(VERSION 3.5...3.16)
cmake_minimum_required(VERSION 3.5)
project(BoostVariant2 LANGUAGES CXX)
project(boost_variant2 VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
add_library(boost_variant2 INTERFACE)
add_library(Boost::variant2 ALIAS boost_variant2)
@@ -15,7 +12,13 @@ add_library(Boost::variant2 ALIAS boost_variant2)
target_include_directories(boost_variant2 INTERFACE include)
target_link_libraries(boost_variant2
INTERFACE
Boost::config
Boost::mp11
INTERFACE
Boost::config
Boost::mp11
)
if(BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -1,4 +1,4 @@
# Copyright 2016-2018 Peter Dimov
# Copyright 2016-2020 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)
@@ -21,6 +21,14 @@ environment:
TOOLSET: msvc-14.1
ADDRMD: 32,64
CXXSTD: 14,17
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: clang-win
ADDRMD: 64
CXXSTD: 14,17
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: msvc-14.2
ADDRMD: 32,64
CXXSTD: 14,17
install:
- set BOOST_BRANCH=develop
@@ -28,8 +36,6 @@ install:
- cd ..
- git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
- cd boost-root
- git submodule update --init tools/build
- git submodule update --init libs/config
- git submodule update --init tools/boostdep
- xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\variant2\
- python tools/boostdep/depinst/depinst.py variant2
@@ -41,4 +47,4 @@ build: off
test_script:
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
- b2 libs/variant2/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release
- b2 -j3 libs/variant2/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release

View File

@@ -1,5 +1,5 @@
////
Copyright 2019 Peter Dimov
Copyright 2019, 2020 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
@@ -11,6 +11,19 @@ http://www.boost.org/LICENSE_1_0.txt
# Revision History
:idprefix: changelog_
## Changes in 1.74.0
* Added support for derived types in `visit`
* Improved compilation performance for many (hundreds of) alternatives.
* Added support for `visit<R>`
## Changes in 1.73.0
* Added support for `std::hash`, `boost::hash`.
* `variant<T...>` is now trivial when all types in `T...` are trivial.
This improves performance by enabling it to be passed to, and returned
from, functions in registers.
## Changes in 1.71.0
After the Boost formal review, the implementation has been

View File

@@ -169,8 +169,6 @@ The main differences between this implementation and `std::variant` are:
`variant<int, float>` is provided as the member function `subset<U...>`.
(This operation can throw if the current state of the variant cannot be
represented.)
* `variant<T...>` is not (yet) trivial when all contained types are trivial,
as mandated by {cpp}17.
* The {cpp}20 additions and changes to `std::variant` have not yet been
implemented.

View File

@@ -134,7 +134,7 @@ template<class... T>
// visit
template<class F, class... V>
template<class R = /*unspecified*/, class F, class... V>
constexpr /*see below*/ visit(F&& f, V&&... v);
// monostate
@@ -838,7 +838,7 @@ Returns: ::
### visit
```
template<class F, class... V>
template<class R = /*unspecified*/, class F, class... V>
constexpr /*see below*/ visit(F&& f, V&&... v);
```
[none]
@@ -846,6 +846,10 @@ template<class F, class... V>
+
Returns: :: `std::forward<F>(f)(get<I>(std::forward<V>(v))...)`, where
`I...` is `v.index()...`.
Remarks: :: If `R` is given explicitly, as in `visit<int>`, the return
type is `R`. Otherwise, it's deduced from `F`. All possible applications
of `F` to the variant alternatives must have the same return type for
this deduction to succeed.
### swap

View File

@@ -18,12 +18,14 @@
#endif
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/cstdint.hpp>
#include <cstddef>
#include <type_traits>
#include <exception>
#include <cassert>
#include <initializer_list>
#include <utility>
#include <functional> // std::hash
//
@@ -502,11 +504,23 @@ using std::is_trivially_move_assignable;
#endif
#if defined( BOOST_LIBSTDCXX_VERSION ) && BOOST_LIBSTDCXX_VERSION < 40800
template<class T> struct is_trivially_destructible: std::has_trivial_destructor<T>
{
};
#else
using std::is_trivially_destructible;
#endif
// variant_storage
template<class D, class... T> union variant_storage_impl;
template<class... T> using variant_storage = variant_storage_impl<mp11::mp_all<std::is_trivially_destructible<T>...>, T...>;
template<class... T> using variant_storage = variant_storage_impl<mp11::mp_all<detail::is_trivially_destructible<T>...>, T...>;
template<class D> union variant_storage_impl<D>
{
@@ -547,6 +561,88 @@ template<class T1, class... T> union variant_storage_impl<mp11::mp_false, T1, T.
template<std::size_t I> constexpr mp11::mp_at_c<mp11::mp_list<T...>, I-1> const& get( mp11::mp_size_t<I> ) const noexcept { return rest_.get( mp11::mp_size_t<I-1>() ); }
};
template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class... T> union variant_storage_impl<mp11::mp_false, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T...>
{
T0 t0_;
T1 t1_;
T2 t2_;
T3 t3_;
T4 t4_;
T5 t5_;
T6 t6_;
T7 t7_;
T8 t8_;
T9 t9_;
variant_storage<T...> rest_;
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward<A>(a)... ) {}
template<std::size_t I, class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), std::forward<A>(a)... ) {}
~variant_storage_impl()
{
}
template<class... A> void emplace( mp11::mp_size_t<0>, A&&... a ) { ::new( &t0_ ) T0( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<1>, A&&... a ) { ::new( &t1_ ) T1( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<2>, A&&... a ) { ::new( &t2_ ) T2( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<3>, A&&... a ) { ::new( &t3_ ) T3( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<4>, A&&... a ) { ::new( &t4_ ) T4( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<5>, A&&... a ) { ::new( &t5_ ) T5( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<6>, A&&... a ) { ::new( &t6_ ) T6( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<7>, A&&... a ) { ::new( &t7_ ) T7( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<8>, A&&... a ) { ::new( &t8_ ) T8( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<9>, A&&... a ) { ::new( &t9_ ) T9( std::forward<A>(a)... ); }
template<std::size_t I, class... A> void emplace( mp11::mp_size_t<I>, A&&... a )
{
rest_.emplace( mp11::mp_size_t<I-10>(), std::forward<A>(a)... );
}
BOOST_CXX14_CONSTEXPR T0& get( mp11::mp_size_t<0> ) noexcept { return t0_; }
constexpr T0 const& get( mp11::mp_size_t<0> ) const noexcept { return t0_; }
BOOST_CXX14_CONSTEXPR T1& get( mp11::mp_size_t<1> ) noexcept { return t1_; }
constexpr T1 const& get( mp11::mp_size_t<1> ) const noexcept { return t1_; }
BOOST_CXX14_CONSTEXPR T2& get( mp11::mp_size_t<2> ) noexcept { return t2_; }
constexpr T2 const& get( mp11::mp_size_t<2> ) const noexcept { return t2_; }
BOOST_CXX14_CONSTEXPR T3& get( mp11::mp_size_t<3> ) noexcept { return t3_; }
constexpr T3 const& get( mp11::mp_size_t<3> ) const noexcept { return t3_; }
BOOST_CXX14_CONSTEXPR T4& get( mp11::mp_size_t<4> ) noexcept { return t4_; }
constexpr T4 const& get( mp11::mp_size_t<4> ) const noexcept { return t4_; }
BOOST_CXX14_CONSTEXPR T5& get( mp11::mp_size_t<5> ) noexcept { return t5_; }
constexpr T5 const& get( mp11::mp_size_t<5> ) const noexcept { return t5_; }
BOOST_CXX14_CONSTEXPR T6& get( mp11::mp_size_t<6> ) noexcept { return t6_; }
constexpr T6 const& get( mp11::mp_size_t<6> ) const noexcept { return t6_; }
BOOST_CXX14_CONSTEXPR T7& get( mp11::mp_size_t<7> ) noexcept { return t7_; }
constexpr T7 const& get( mp11::mp_size_t<7> ) const noexcept { return t7_; }
BOOST_CXX14_CONSTEXPR T8& get( mp11::mp_size_t<8> ) noexcept { return t8_; }
constexpr T8 const& get( mp11::mp_size_t<8> ) const noexcept { return t8_; }
BOOST_CXX14_CONSTEXPR T9& get( mp11::mp_size_t<9> ) noexcept { return t9_; }
constexpr T9 const& get( mp11::mp_size_t<9> ) const noexcept { return t9_; }
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<mp11::mp_list<T...>, I-10>& get( mp11::mp_size_t<I> ) noexcept { return rest_.get( mp11::mp_size_t<I-10>() ); }
template<std::size_t I> constexpr mp11::mp_at_c<mp11::mp_list<T...>, I-10> const& get( mp11::mp_size_t<I> ) const noexcept { return rest_.get( mp11::mp_size_t<I-10>() ); }
};
// all trivially destructible
template<class T1, class... T> union variant_storage_impl<mp11::mp_true, T1, T...>
{
@@ -588,6 +684,105 @@ template<class T1, class... T> union variant_storage_impl<mp11::mp_true, T1, T..
template<std::size_t I> constexpr mp11::mp_at_c<mp11::mp_list<T...>, I-1> const& get( mp11::mp_size_t<I> ) const noexcept { return rest_.get( mp11::mp_size_t<I-1>() ); }
};
template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class... T> union variant_storage_impl<mp11::mp_true, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T...>
{
T0 t0_;
T1 t1_;
T2 t2_;
T3 t3_;
T4 t4_;
T5 t5_;
T6 t6_;
T7 t7_;
T8 t8_;
T9 t9_;
variant_storage<T...> rest_;
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward<A>(a)... ) {}
template<std::size_t I, class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), std::forward<A>(a)... ) {}
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<0>, A&&... a ) { ::new( &t0_ ) T0( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<1>, A&&... a ) { ::new( &t1_ ) T1( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<2>, A&&... a ) { ::new( &t2_ ) T2( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<3>, A&&... a ) { ::new( &t3_ ) T3( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<4>, A&&... a ) { ::new( &t4_ ) T4( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<5>, A&&... a ) { ::new( &t5_ ) T5( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<6>, A&&... a ) { ::new( &t6_ ) T6( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<7>, A&&... a ) { ::new( &t7_ ) T7( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<8>, A&&... a ) { ::new( &t8_ ) T8( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<9>, A&&... a ) { ::new( &t9_ ) T9( std::forward<A>(a)... ); }
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<I>, A&&... a )
{
rest_.emplace( mp11::mp_size_t<I-10>(), std::forward<A>(a)... );
}
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_true, mp11::mp_size_t<I>, A&&... a )
{
*this = variant_storage_impl( mp11::mp_size_t<I>(), std::forward<A>(a)... );
}
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<I>, A&&... a )
{
this->emplace_impl( mp11::mp_all<
detail::is_trivially_move_assignable<T0>,
detail::is_trivially_move_assignable<T1>,
detail::is_trivially_move_assignable<T2>,
detail::is_trivially_move_assignable<T3>,
detail::is_trivially_move_assignable<T4>,
detail::is_trivially_move_assignable<T5>,
detail::is_trivially_move_assignable<T6>,
detail::is_trivially_move_assignable<T7>,
detail::is_trivially_move_assignable<T8>,
detail::is_trivially_move_assignable<T9>,
detail::is_trivially_move_assignable<T>...>(), mp11::mp_size_t<I>(), std::forward<A>(a)... );
}
BOOST_CXX14_CONSTEXPR T0& get( mp11::mp_size_t<0> ) noexcept { return t0_; }
constexpr T0 const& get( mp11::mp_size_t<0> ) const noexcept { return t0_; }
BOOST_CXX14_CONSTEXPR T1& get( mp11::mp_size_t<1> ) noexcept { return t1_; }
constexpr T1 const& get( mp11::mp_size_t<1> ) const noexcept { return t1_; }
BOOST_CXX14_CONSTEXPR T2& get( mp11::mp_size_t<2> ) noexcept { return t2_; }
constexpr T2 const& get( mp11::mp_size_t<2> ) const noexcept { return t2_; }
BOOST_CXX14_CONSTEXPR T3& get( mp11::mp_size_t<3> ) noexcept { return t3_; }
constexpr T3 const& get( mp11::mp_size_t<3> ) const noexcept { return t3_; }
BOOST_CXX14_CONSTEXPR T4& get( mp11::mp_size_t<4> ) noexcept { return t4_; }
constexpr T4 const& get( mp11::mp_size_t<4> ) const noexcept { return t4_; }
BOOST_CXX14_CONSTEXPR T5& get( mp11::mp_size_t<5> ) noexcept { return t5_; }
constexpr T5 const& get( mp11::mp_size_t<5> ) const noexcept { return t5_; }
BOOST_CXX14_CONSTEXPR T6& get( mp11::mp_size_t<6> ) noexcept { return t6_; }
constexpr T6 const& get( mp11::mp_size_t<6> ) const noexcept { return t6_; }
BOOST_CXX14_CONSTEXPR T7& get( mp11::mp_size_t<7> ) noexcept { return t7_; }
constexpr T7 const& get( mp11::mp_size_t<7> ) const noexcept { return t7_; }
BOOST_CXX14_CONSTEXPR T8& get( mp11::mp_size_t<8> ) noexcept { return t8_; }
constexpr T8 const& get( mp11::mp_size_t<8> ) const noexcept { return t8_; }
BOOST_CXX14_CONSTEXPR T9& get( mp11::mp_size_t<9> ) noexcept { return t9_; }
constexpr T9 const& get( mp11::mp_size_t<9> ) const noexcept { return t9_; }
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<mp11::mp_list<T...>, I-10>& get( mp11::mp_size_t<I> ) noexcept { return rest_.get( mp11::mp_size_t<I-10>() ); }
template<std::size_t I> constexpr mp11::mp_at_c<mp11::mp_list<T...>, I-10> const& get( mp11::mp_size_t<I> ) const noexcept { return rest_.get( mp11::mp_size_t<I-10>() ); }
};
// resolve_overload_*
template<class... T> struct overload;
@@ -624,7 +819,7 @@ template<class U, class... T> using resolve_overload_index = mp11::mp_find<mp11:
// variant_base
template<bool is_trivially_destructible, bool is_single_buffered, class... T> struct variant_base_impl;
template<class... T> using variant_base = variant_base_impl<mp11::mp_all<std::is_trivially_destructible<T>...>::value, mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value, T...>;
template<class... T> using variant_base = variant_base_impl<mp11::mp_all<detail::is_trivially_destructible<T>...>::value, mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value, T...>;
struct none {};
@@ -1050,20 +1245,317 @@ template<class T> struct is_nothrow_swappable: mp11::mp_valid<det2::is_nothrow_s
#endif
// variant_cc_base
template<bool CopyConstructible, bool TriviallyCopyConstructible, class... T> struct variant_cc_base_impl;
template<class... T> using variant_cc_base = variant_cc_base_impl<
mp11::mp_all<std::is_copy_constructible<T>...>::value,
mp11::mp_all<detail::is_trivially_copy_constructible<T>...>::value,
T...>;
template<class... T> struct variant_cc_base_impl<true, true, T...>: public variant_base<T...>
{
using variant_base = detail::variant_base<T...>;
using variant_base::variant_base;
variant_cc_base_impl() = default;
variant_cc_base_impl( variant_cc_base_impl const& ) = default;
variant_cc_base_impl( variant_cc_base_impl && ) = default;
variant_cc_base_impl& operator=( variant_cc_base_impl const& ) = default;
variant_cc_base_impl& operator=( variant_cc_base_impl && ) = default;
};
template<bool B, class... T> struct variant_cc_base_impl<false, B, T...>: public variant_base<T...>
{
using variant_base = detail::variant_base<T...>;
using variant_base::variant_base;
variant_cc_base_impl() = default;
variant_cc_base_impl( variant_cc_base_impl const& ) = delete;
variant_cc_base_impl( variant_cc_base_impl && ) = default;
variant_cc_base_impl& operator=( variant_cc_base_impl const& ) = default;
variant_cc_base_impl& operator=( variant_cc_base_impl && ) = default;
};
template<class... T> struct variant_cc_base_impl<true, false, T...>: public variant_base<T...>
{
using variant_base = detail::variant_base<T...>;
using variant_base::variant_base;
public:
// constructors
variant_cc_base_impl() = default;
// copy constructor
private:
struct L1
{
variant_base * this_;
variant_base const & r;
template<class I> void operator()( I i ) const
{
this_->_replace( i, r._get_impl( i ) );
}
};
public:
variant_cc_base_impl( variant_cc_base_impl const& r )
noexcept( mp11::mp_all<std::is_nothrow_copy_constructible<T>...>::value )
: variant_base()
{
mp11::mp_with_index<sizeof...(T)>( r.index(), L1{ this, r } );
}
// move constructor
variant_cc_base_impl( variant_cc_base_impl && ) = default;
// assignment
variant_cc_base_impl& operator=( variant_cc_base_impl const & ) = default;
variant_cc_base_impl& operator=( variant_cc_base_impl && ) = default;
};
// variant_ca_base
template<bool CopyAssignable, bool TriviallyCopyAssignable, class... T> struct variant_ca_base_impl;
template<class... T> using variant_ca_base = variant_ca_base_impl<
mp11::mp_all<std::is_copy_constructible<T>..., std::is_copy_assignable<T>...>::value,
mp11::mp_all<detail::is_trivially_destructible<T>..., detail::is_trivially_copy_constructible<T>..., detail::is_trivially_copy_assignable<T>...>::value,
T...>;
template<class... T> struct variant_ca_base_impl<true, true, T...>: public variant_cc_base<T...>
{
using variant_base = detail::variant_cc_base<T...>;
using variant_base::variant_base;
variant_ca_base_impl() = default;
variant_ca_base_impl( variant_ca_base_impl const& ) = default;
variant_ca_base_impl( variant_ca_base_impl && ) = default;
variant_ca_base_impl& operator=( variant_ca_base_impl const& ) = default;
variant_ca_base_impl& operator=( variant_ca_base_impl && ) = default;
};
template<bool B, class... T> struct variant_ca_base_impl<false, B, T...>: public variant_cc_base<T...>
{
using variant_base = detail::variant_cc_base<T...>;
using variant_base::variant_base;
variant_ca_base_impl() = default;
variant_ca_base_impl( variant_ca_base_impl const& ) = default;
variant_ca_base_impl( variant_ca_base_impl && ) = default;
variant_ca_base_impl& operator=( variant_ca_base_impl const& ) = delete;
variant_ca_base_impl& operator=( variant_ca_base_impl && ) = default;
};
template<class... T> struct variant_ca_base_impl<true, false, T...>: public variant_cc_base<T...>
{
using variant_base = detail::variant_cc_base<T...>;
using variant_base::variant_base;
public:
// constructors
variant_ca_base_impl() = default;
variant_ca_base_impl( variant_ca_base_impl const& ) = default;
variant_ca_base_impl( variant_ca_base_impl && ) = default;
// copy assignment
private:
struct L3
{
variant_base * this_;
variant_base const & r;
template<class I> void operator()( I i ) const
{
this_->template emplace<I::value>( r._get_impl( i ) );
}
};
public:
BOOST_CXX14_CONSTEXPR variant_ca_base_impl& operator=( variant_ca_base_impl const & r )
noexcept( mp11::mp_all<std::is_nothrow_copy_constructible<T>...>::value )
{
mp11::mp_with_index<sizeof...(T)>( r.index(), L3{ this, r } );
return *this;
}
// move assignment
variant_ca_base_impl& operator=( variant_ca_base_impl && ) = default;
};
// variant_mc_base
template<bool MoveConstructible, bool TriviallyMoveConstructible, class... T> struct variant_mc_base_impl;
template<class... T> using variant_mc_base = variant_mc_base_impl<
mp11::mp_all<std::is_move_constructible<T>...>::value,
mp11::mp_all<detail::is_trivially_move_constructible<T>...>::value,
T...>;
template<class... T> struct variant_mc_base_impl<true, true, T...>: public variant_ca_base<T...>
{
using variant_base = detail::variant_ca_base<T...>;
using variant_base::variant_base;
variant_mc_base_impl() = default;
variant_mc_base_impl( variant_mc_base_impl const& ) = default;
variant_mc_base_impl( variant_mc_base_impl && ) = default;
variant_mc_base_impl& operator=( variant_mc_base_impl const& ) = default;
variant_mc_base_impl& operator=( variant_mc_base_impl && ) = default;
};
template<bool B, class... T> struct variant_mc_base_impl<false, B, T...>: public variant_ca_base<T...>
{
using variant_base = detail::variant_ca_base<T...>;
using variant_base::variant_base;
variant_mc_base_impl() = default;
variant_mc_base_impl( variant_mc_base_impl const& ) = default;
variant_mc_base_impl( variant_mc_base_impl && ) = delete;
variant_mc_base_impl& operator=( variant_mc_base_impl const& ) = default;
variant_mc_base_impl& operator=( variant_mc_base_impl && ) = default;
};
template<class... T> struct variant_mc_base_impl<true, false, T...>: public variant_ca_base<T...>
{
using variant_base = detail::variant_ca_base<T...>;
using variant_base::variant_base;
public:
// constructors
variant_mc_base_impl() = default;
variant_mc_base_impl( variant_mc_base_impl const& ) = default;
// move constructor
private:
struct L2
{
variant_base * this_;
variant_base & r;
template<class I> void operator()( I i ) const
{
this_->_replace( i, std::move( r._get_impl( i ) ) );
}
};
public:
variant_mc_base_impl( variant_mc_base_impl && r )
noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value )
{
mp11::mp_with_index<sizeof...(T)>( r.index(), L2{ this, r } );
}
// assignment
variant_mc_base_impl& operator=( variant_mc_base_impl const & ) = default;
variant_mc_base_impl& operator=( variant_mc_base_impl && ) = default;
};
// variant_ma_base
template<bool MoveAssignable, bool TriviallyMoveAssignable, class... T> struct variant_ma_base_impl;
template<class... T> using variant_ma_base = variant_ma_base_impl<
mp11::mp_all<std::is_move_constructible<T>..., std::is_move_assignable<T>...>::value,
mp11::mp_all<detail::is_trivially_destructible<T>..., detail::is_trivially_move_constructible<T>..., detail::is_trivially_move_assignable<T>...>::value,
T...>;
template<class... T> struct variant_ma_base_impl<true, true, T...>: public variant_mc_base<T...>
{
using variant_base = detail::variant_mc_base<T...>;
using variant_base::variant_base;
variant_ma_base_impl() = default;
variant_ma_base_impl( variant_ma_base_impl const& ) = default;
variant_ma_base_impl( variant_ma_base_impl && ) = default;
variant_ma_base_impl& operator=( variant_ma_base_impl const& ) = default;
variant_ma_base_impl& operator=( variant_ma_base_impl && ) = default;
};
template<bool B, class... T> struct variant_ma_base_impl<false, B, T...>: public variant_mc_base<T...>
{
using variant_base = detail::variant_mc_base<T...>;
using variant_base::variant_base;
variant_ma_base_impl() = default;
variant_ma_base_impl( variant_ma_base_impl const& ) = default;
variant_ma_base_impl( variant_ma_base_impl && ) = default;
variant_ma_base_impl& operator=( variant_ma_base_impl const& ) = default;
variant_ma_base_impl& operator=( variant_ma_base_impl && ) = delete;
};
template<class... T> struct variant_ma_base_impl<true, false, T...>: public variant_mc_base<T...>
{
using variant_base = detail::variant_mc_base<T...>;
using variant_base::variant_base;
public:
// constructors
variant_ma_base_impl() = default;
variant_ma_base_impl( variant_ma_base_impl const& ) = default;
variant_ma_base_impl( variant_ma_base_impl && ) = default;
// copy assignment
variant_ma_base_impl& operator=( variant_ma_base_impl const & ) = default;
// move assignment
private:
struct L4
{
variant_base * this_;
variant_base & r;
template<class I> void operator()( I i ) const
{
this_->template emplace<I::value>( std::move( r._get_impl( i ) ) );
}
};
public:
variant_ma_base_impl& operator=( variant_ma_base_impl && r )
noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value )
{
mp11::mp_with_index<sizeof...(T)>( r.index(), L4{ this, r } );
return *this;
}
};
} // namespace detail
// variant
template<class... T> class variant: private detail::variant_base<T...>
template<class... T> class variant: private detail::variant_ma_base<T...>
{
private:
using variant_base = detail::variant_base<T...>;
private:
variant( variant const volatile& r ) = delete;
variant& operator=( variant const volatile& r ) = delete;
using variant_base = detail::variant_ma_base<T...>;
public:
@@ -1076,71 +1568,8 @@ public:
{
}
template<class E1 = void,
class E2 = mp11::mp_if<mp11::mp_all<detail::is_trivially_copy_constructible<T>...>, E1>
>
constexpr variant( variant const& r ) noexcept
: variant_base( static_cast<variant_base const&>(r) )
{
}
private:
struct L1
{
variant_base * this_;
variant const & r;
template<class I> void operator()( I i ) const
{
this_->_replace( i, r._get_impl( i ) );
}
};
public:
template<class E1 = void,
class E2 = mp11::mp_if<mp11::mp_not<mp11::mp_all<detail::is_trivially_copy_constructible<T>...>>, E1>,
class E3 = mp11::mp_if<mp11::mp_all<std::is_copy_constructible<T>...>, E1>
>
variant( variant const& r )
noexcept( mp11::mp_all<std::is_nothrow_copy_constructible<T>...>::value )
{
mp11::mp_with_index<sizeof...(T)>( r.index(), L1{ this, r } );
}
template<class E1 = void,
class E2 = mp11::mp_if<mp11::mp_all<detail::is_trivially_move_constructible<T>...>, E1>
>
constexpr variant( variant && r ) noexcept
: variant_base( static_cast<variant_base&&>(r) )
{
}
private:
struct L2
{
variant_base * this_;
variant & r;
template<class I> void operator()( I i ) const
{
this_->_replace( i, std::move( r._get_impl( i ) ) );
}
};
public:
template<class E1 = void,
class E2 = mp11::mp_if<mp11::mp_not<mp11::mp_all<detail::is_trivially_move_constructible<T>...>>, E1>,
class E3 = mp11::mp_if<mp11::mp_all<std::is_move_constructible<T>...>, E1>
>
variant( variant && r )
noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value )
{
mp11::mp_with_index<sizeof...(T)>( r.index(), L2{ this, r } );
}
// variant( variant const& ) = default;
// variant( variant && ) = default;
template<class U,
class Ud = typename std::decay<U>::type,
@@ -1175,75 +1604,9 @@ public:
}
// assignment
template<class E1 = void,
class E2 = mp11::mp_if<mp11::mp_all<std::is_trivially_destructible<T>..., detail::is_trivially_copy_constructible<T>..., detail::is_trivially_copy_assignable<T>...>, E1>
>
BOOST_CXX14_CONSTEXPR variant& operator=( variant const & r ) noexcept
{
static_cast<variant_base&>( *this ) = static_cast<variant_base const&>( r );
return *this;
}
private:
struct L3
{
variant * this_;
variant const & r;
template<class I> void operator()( I i ) const
{
this_->variant_base::template emplace<I::value>( r._get_impl( i ) );
}
};
public:
template<class E1 = void,
class E2 = mp11::mp_if<mp11::mp_not<mp11::mp_all<std::is_trivially_destructible<T>..., detail::is_trivially_copy_constructible<T>..., detail::is_trivially_copy_assignable<T>...>>, E1>,
class E3 = mp11::mp_if<mp11::mp_all<std::is_copy_constructible<T>..., std::is_copy_assignable<T>...>, E1>
>
BOOST_CXX14_CONSTEXPR variant& operator=( variant const & r )
noexcept( mp11::mp_all<std::is_nothrow_copy_constructible<T>...>::value )
{
mp11::mp_with_index<sizeof...(T)>( r.index(), L3{ this, r } );
return *this;
}
template<class E1 = void,
class E2 = mp11::mp_if<mp11::mp_all<std::is_trivially_destructible<T>..., detail::is_trivially_move_constructible<T>..., detail::is_trivially_move_assignable<T>...>, E1>
>
BOOST_CXX14_CONSTEXPR variant& operator=( variant && r ) noexcept
{
static_cast<variant_base&>( *this ) = static_cast<variant_base&&>( r );
return *this;
}
private:
struct L4
{
variant * this_;
variant & r;
template<class I> void operator()( I i ) const
{
this_->variant_base::template emplace<I::value>( std::move( r._get_impl( i ) ) );
}
};
public:
template<class E1 = void,
class E2 = mp11::mp_if<mp11::mp_not<mp11::mp_all<std::is_trivially_destructible<T>..., detail::is_trivially_move_constructible<T>..., detail::is_trivially_move_assignable<T>...>>, E1>,
class E3 = mp11::mp_if<mp11::mp_all<std::is_move_constructible<T>..., std::is_move_assignable<T>...>, E1>
>
variant& operator=( variant && r )
noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value )
{
mp11::mp_with_index<sizeof...(T)>( r.index(), L4{ this, r } );
return *this;
}
// variant& operator=( variant const& ) = default;
// variant& operator=( variant && ) = default;
template<class U,
class E1 = typename std::enable_if<!std::is_same<typename std::decay<U>::type, variant>::value>::type,
@@ -1598,6 +1961,25 @@ namespace detail
template<class T> using remove_cv_ref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template<class... T> variant<T...> const & extract_variant_base_( variant<T...> const & );
#if BOOST_WORKAROUND( BOOST_MSVC, < 1930 )
template<class V> struct extract_vbase_impl
{
using type = decltype( extract_variant_base_( std::declval<V>() ) );
};
template<class V> using extract_variant_base = remove_cv_ref_t< typename extract_vbase_impl<V>::type >;
#else
template<class V> using extract_variant_base = remove_cv_ref_t< decltype( extract_variant_base_( std::declval<V>() ) ) >;
#endif
template<class V> using variant_base_size = variant_size< extract_variant_base<V> >;
template<class T, class U> struct copy_cv_ref
{
using type = T;
@@ -1637,13 +2019,28 @@ template<class F> struct Qret
template<class L> using front_if_same = mp11::mp_if<mp11::mp_apply<mp11::mp_same, L>, mp11::mp_front<L>>;
template<class V> using apply_cv_ref = mp11::mp_product<copy_cv_ref_t, remove_cv_ref_t<V>, mp11::mp_list<V>>;
template<class V> using apply_cv_ref = mp11::mp_product<copy_cv_ref_t, extract_variant_base<V>, mp11::mp_list<V>>;
template<class F, class... V> using Vret = front_if_same<mp11::mp_product_q<Qret<F>, apply_cv_ref<V>...>>;
struct deduced {};
#if !BOOST_WORKAROUND( BOOST_MSVC, < 1920 )
template<class R, class F, class... V> using Vret = mp11::mp_eval_if_not< std::is_same<R, deduced>, R, front_if_same, mp11::mp_product_q<Qret<F>, apply_cv_ref<V>...> >;
#else
template<class R, class F, class... V> struct Vret_impl
{
using type = mp11::mp_eval_if_not< std::is_same<R, deduced>, R, front_if_same, mp11::mp_product_q<Qret<F>, apply_cv_ref<V>...> >;
};
template<class R, class F, class... V> using Vret = typename Vret_impl<R, F, V...>::type;
#endif
} // namespace detail
template<class F> constexpr auto visit( F&& f ) -> decltype(std::forward<F>(f)())
template<class R = detail::deduced, class F> constexpr auto visit( F&& f ) -> detail::Vret<R, F>
{
return std::forward<F>(f)();
}
@@ -1651,12 +2048,12 @@ template<class F> constexpr auto visit( F&& f ) -> decltype(std::forward<F>(f)()
namespace detail
{
template<class F, class V1> struct visit_L1
template<class R, class F, class V1> struct visit_L1
{
F&& f;
V1&& v1;
template<class I> auto operator()( I ) const -> Vret<F, V1>
template<class I> auto operator()( I ) const -> Vret<R, F, V1>
{
return std::forward<F>(f)( unsafe_get<I::value>( std::forward<V1>(v1) ) );
}
@@ -1664,9 +2061,9 @@ template<class F, class V1> struct visit_L1
} // namespace detail
template<class F, class V1> constexpr auto visit( F&& f, V1&& v1 ) -> detail::Vret<F, V1>
template<class R = detail::deduced, class F, class V1> constexpr auto visit( F&& f, V1&& v1 ) -> detail::Vret<R, F, V1>
{
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L1<F, V1>{ std::forward<F>(f), std::forward<V1>(v1) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L1<R, F, V1>{ std::forward<F>(f), std::forward<V1>(v1) } );
}
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) || BOOST_WORKAROUND( BOOST_MSVC, < 1920 )
@@ -1690,31 +2087,31 @@ template<class F, class A> bind_front_<F, A> bind_front( F&& f, A&& a )
return bind_front_<F, A>{ std::forward<F>(f), std::forward<A>(a) };
}
template<class F, class V1, class V2> struct visit_L2
template<class R, class F, class V1, class V2> struct visit_L2
{
F&& f;
V1&& v1;
V2&& v2;
template<class I> auto operator()( I ) const -> Vret<F, V1, V2>
template<class I> auto operator()( I ) const -> Vret<R, F, V1, V2>
{
auto f2 = bind_front( std::forward<F>(f), unsafe_get<I::value>( std::forward<V1>(v1) ) );
return visit( f2, std::forward<V2>(v2) );
return visit<R>( f2, std::forward<V2>(v2) );
}
};
} // namespace detail
template<class F, class V1, class V2> constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> detail::Vret<F, V1, V2>
template<class R = detail::deduced, class F, class V1, class V2> constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> detail::Vret<R, F, V1, V2>
{
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L2<F, V1, V2>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L2<R, F, V1, V2>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2) } );
}
namespace detail
{
template<class F, class V1, class V2, class V3> struct visit_L3
template<class R, class F, class V1, class V2, class V3> struct visit_L3
{
F&& f;
@@ -1722,24 +2119,24 @@ template<class F, class V1, class V2, class V3> struct visit_L3
V2&& v2;
V3&& v3;
template<class I> auto operator()( I ) const -> Vret<F, V1, V2, V3>
template<class I> auto operator()( I ) const -> Vret<R, F, V1, V2, V3>
{
auto f2 = bind_front( std::forward<F>(f), unsafe_get<I::value>( std::forward<V1>(v1) ) );
return visit( f2, std::forward<V2>(v2), std::forward<V3>(v3) );
return visit<R>( f2, std::forward<V2>(v2), std::forward<V3>(v3) );
}
};
} // namespace detail
template<class F, class V1, class V2, class V3> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> detail::Vret<F, V1, V2, V3>
template<class R = detail::deduced, class F, class V1, class V2, class V3> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> detail::Vret<R, F, V1, V2, V3>
{
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L3<F, V1, V2, V3>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L3<R, F, V1, V2, V3>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3) } );
}
namespace detail
{
template<class F, class V1, class V2, class V3, class V4> struct visit_L4
template<class R, class F, class V1, class V2, class V3, class V4> struct visit_L4
{
F&& f;
@@ -1748,28 +2145,28 @@ template<class F, class V1, class V2, class V3, class V4> struct visit_L4
V3&& v3;
V4&& v4;
template<class I> auto operator()( I ) const -> Vret<F, V1, V2, V3, V4>
template<class I> auto operator()( I ) const -> Vret<R, F, V1, V2, V3, V4>
{
auto f2 = bind_front( std::forward<F>(f), unsafe_get<I::value>( std::forward<V1>(v1) ) );
return visit( f2, std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) );
return visit<R>( f2, std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) );
}
};
} // namespace detail
template<class F, class V1, class V2, class V3, class V4> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3, V4&& v4 ) -> detail::Vret<F, V1, V2, V3, V4>
template<class R = detail::deduced, class F, class V1, class V2, class V3, class V4> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3, V4&& v4 ) -> detail::Vret<R, F, V1, V2, V3, V4>
{
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L4<F, V1, V2, V3, V4>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) } );
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L4<R, F, V1, V2, V3, V4>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) } );
}
#else
template<class F, class V1, class V2, class... V> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V&&... v ) -> detail::Vret<F, V1, V2, V...>
template<class R = detail::deduced, class F, class V1, class V2, class... V> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V&&... v ) -> detail::Vret<R, F, V1, V2, V...>
{
return mp11::mp_with_index<variant_size<V1>>( v1.index(), [&]( auto I ){
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), [&]( auto I ){
auto f2 = [&]( auto&&... a ){ return std::forward<F>(f)( detail::unsafe_get<I.value>( std::forward<V1>(v1) ), std::forward<decltype(a)>(a)... ); };
return visit( f2, std::forward<V2>(v2), std::forward<V>(v)... );
return visit<R>( f2, std::forward<V2>(v2), std::forward<V>(v)... );
});
}
@@ -1785,9 +2182,92 @@ void swap( variant<T...> & v, variant<T...> & w )
v.swap( w );
}
// hashing support
namespace detail
{
template<class V> struct hash_value_L
{
V const & v;
template<class I> std::size_t operator()( I ) const
{
boost::ulong_long_type hv = ( boost::ulong_long_type( 0xCBF29CE4 ) << 32 ) + 0x84222325;
boost::ulong_long_type const prime = ( boost::ulong_long_type( 0x00000100 ) << 32 ) + 0x000001B3;
// index
hv ^= I::value;
hv *= prime;
// value
auto const & t = unsafe_get<I::value>( v );
hv ^= std::hash<remove_cv_ref_t<decltype(t)>>()( t );
hv *= prime;
return static_cast<std::size_t>( hv );
}
};
} // namespace detail
inline std::size_t hash_value( monostate const & )
{
return 0xA7EE4757u;
}
template<class... T> std::size_t hash_value( variant<T...> const & v )
{
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::hash_value_L< variant<T...> >{ v } );
}
namespace detail
{
template<class T> using is_hash_enabled = std::is_default_constructible< std::hash<typename std::remove_const<T>::type> >;
template<class V, bool E = mp11::mp_all_of<V, is_hash_enabled>::value> struct std_hash_impl;
template<class V> struct std_hash_impl<V, false>
{
std_hash_impl() = delete;
std_hash_impl( std_hash_impl const& ) = delete;
std_hash_impl& operator=( std_hash_impl const& ) = delete;
};
template<class V> struct std_hash_impl<V, true>
{
std::size_t operator()( V const & v ) const
{
return hash_value( v );
}
};
} // namespace detail
} // namespace variant2
} // namespace boost
namespace std
{
template<class... T> struct hash< ::boost::variant2::variant<T...> >: public ::boost::variant2::detail::std_hash_impl< ::boost::variant2::variant<T...> >
{
};
template<> struct hash< ::boost::variant2::monostate >
{
std::size_t operator()( ::boost::variant2::monostate const & v ) const
{
return hash_value( v );
}
};
} // namespace std
#if defined(_MSC_VER) && _MSC_VER < 1910
# pragma warning( pop )
#endif

View File

@@ -5,10 +5,11 @@
"Peter Dimov"
],
"maintainers": [
"Peter Dimov <pdimov -at- pdimov.com>"
"Peter Dimov <pdimov -at- gmail.com>"
],
"description": "A never-valueless, strong guarantee implementation of std::variant.",
"category": [
"Containers", "Data"
]
],
"cxxstd": "11"
}

11
test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,11 @@
# 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
include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
if(HAVE_BOOST_TEST)
boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::variant2 Boost::core Boost::container_hash)
endif()

View File

@@ -12,7 +12,7 @@ import ../../config/checks/config : requires ;
project
: default-build
<warnings>all
<warnings>extra
: requirements
@@ -23,20 +23,22 @@ project
<toolset>clang:<warnings-as-errors>on
;
run quick.cpp ;
run variant_size.cpp ;
run variant_alternative.cpp ;
run variant_holds_alternative.cpp ;
compile variant_holds_alternative_cx.cpp ;
compile variant_holds_alternative_cx.cpp : <toolset>msvc-14.0:<build>no ;
run variant_get_by_index.cpp ;
compile variant_get_by_index_cx.cpp ;
compile variant_get_by_index_cx.cpp : <toolset>msvc-14.0:<build>no ;
run variant_get_by_type.cpp ;
compile variant_get_by_type_cx.cpp ;
compile variant_get_by_type_cx.cpp : <toolset>msvc-14.0:<build>no ;
run variant_default_construct.cpp ;
compile variant_default_construct_cx.cpp ;
compile variant_default_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
run variant_copy_construct.cpp ;
compile variant_copy_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
@@ -45,13 +47,13 @@ run variant_move_construct.cpp ;
compile variant_move_construct_cx.cpp : [ requires cxx14_constexpr ] ;
run variant_value_construct.cpp ;
compile variant_value_construct_cx.cpp ;
compile variant_value_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
run variant_in_place_index_construct.cpp ;
compile variant_in_place_index_construct_cx.cpp ;
compile variant_in_place_index_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
run variant_in_place_type_construct.cpp ;
compile variant_in_place_type_construct_cx.cpp ;
compile variant_in_place_type_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
run variant_copy_assign.cpp ;
compile variant_copy_assign_cx.cpp : [ requires cxx14_constexpr ] ;
@@ -97,9 +99,23 @@ local NX =
;
run variant_get_by_index.cpp throw_exception.cpp : : : $(NX) : variant_get_by_index_nx ;
compile variant_get_by_index_cx.cpp : $(NX) : variant_get_by_index_cx_nx ;
compile variant_get_by_index_cx.cpp : $(NX) <toolset>msvc-14.0:<build>no : variant_get_by_index_cx_nx ;
run variant_get_by_type.cpp throw_exception.cpp : : : $(NX) : variant_get_by_type_nx ;
compile variant_get_by_type_cx.cpp : $(NX) : variant_get_by_type_cx_nx ;
compile variant_get_by_type_cx.cpp : $(NX) <toolset>msvc-14.0:<build>no : variant_get_by_type_cx_nx ;
run variant_subset.cpp throw_exception.cpp : : : $(NX) : variant_subset_nx ;
run variant_hash.cpp ;
run variant_trivial.cpp ;
run variant_special.cpp ;
run variant_visit_derived.cpp ;
run variant_many_types.cpp ;
run variant_visit_r.cpp : : :
<toolset>gcc,<target-os>windows:<variant>release
<toolset>gcc,<target-os>cygwin:<variant>release
;

View File

@@ -0,0 +1,17 @@
# 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(cmake_install_test LANGUAGES CXX)
find_package(boost_variant2 REQUIRED)
add_executable(quick ../quick.cpp)
target_link_libraries(quick Boost::variant2)
enable_testing()
add_test(quick quick)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)

View File

@@ -2,7 +2,7 @@
# 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)
cmake_minimum_required(VERSION 3.5...3.16)
project(cmake_subdir_test LANGUAGES CXX)
@@ -10,7 +10,7 @@ add_subdirectory(../.. boostorg/variant2)
add_subdirectory(../../../config boostorg/config)
add_subdirectory(../../../mp11 boostorg/mp11)
add_executable(quick quick.cpp)
add_executable(quick ../quick.cpp)
target_link_libraries(quick Boost::variant2)
enable_testing()

View File

@@ -9,6 +9,8 @@
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <type_traits>
#include <utility>
#include <string>
@@ -48,12 +50,21 @@ struct Y
Y( Y const& ) = delete;
};
struct D
{
~D() {}
};
inline bool operator==( D, D ) { return true; }
template<class V> static void test( V const & v )
{
V v2( v );
BOOST_TEST_EQ( v.index(), v2.index() );
BOOST_TEST( v == v2 );
BOOST_TEST_TRAIT_TRUE((std::is_copy_constructible<V>));
}
int main()
@@ -115,6 +126,12 @@ int main()
test( v );
}
#if !BOOST_WORKAROUND( __GNUC__, < 5 )
test( variant<D>() );
#endif
{
BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible<variant<int>>));
BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible<variant<int const>>));

View File

@@ -57,6 +57,60 @@ STATIC_ASSERT( !std::is_nothrow_move_constructible<X2>::value );
STATIC_ASSERT( !std::is_nothrow_copy_assignable<X2>::value );
STATIC_ASSERT( !std::is_nothrow_move_assignable<X2>::value );
struct Y1
{
int v = 1;
Y1() = default;
Y1(Y1 const&) = delete;
Y1(Y1&&) = delete;
};
STATIC_ASSERT( !std::is_copy_constructible<Y1>::value );
STATIC_ASSERT( !std::is_move_constructible<Y1>::value );
struct Y2
{
int v = 2;
Y2() = default;
Y2(Y2 const&) = delete;
Y2(Y2&&) = delete;
};
STATIC_ASSERT( !std::is_copy_constructible<Y2>::value );
STATIC_ASSERT( !std::is_move_constructible<Y2>::value );
struct Z1
{
static int instances;
int v = 1;
Z1() { ++instances; }
~Z1() { --instances; }
Z1(Z1 const&) = delete;
Z1(Z1&&) = delete;
};
int Z1::instances = 0;
struct Z2
{
static int instances;
int v = 2;
Z2() { ++instances; }
~Z2() { --instances; }
Z2(Z2 const&) = delete;
Z2(Z2&&) = delete;
};
int Z2::instances = 0;
int main()
{
{
@@ -177,5 +231,62 @@ int main()
BOOST_TEST_EQ( get<0>(v).v, 4 );
}
{
variant<Y1, Y2> v;
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
v.emplace<0>();
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
v.emplace<1>();
BOOST_TEST_EQ( v.index(), 1 );
BOOST_TEST_EQ( get<1>(v).v, 2 );
v.emplace<1>();
BOOST_TEST_EQ( v.index(), 1 );
BOOST_TEST_EQ( get<1>(v).v, 2 );
v.emplace<0>();
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
}
{
variant<Z1, Z2> v;
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
BOOST_TEST_EQ( Z1::instances, 1 );
BOOST_TEST_EQ( Z2::instances, 0 );
v.emplace<0>();
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
BOOST_TEST_EQ( Z1::instances, 1 );
BOOST_TEST_EQ( Z2::instances, 0 );
v.emplace<1>();
BOOST_TEST_EQ( v.index(), 1 );
BOOST_TEST_EQ( get<1>(v).v, 2 );
BOOST_TEST_EQ( Z1::instances, 0 );
BOOST_TEST_EQ( Z2::instances, 1 );
v.emplace<1>();
BOOST_TEST_EQ( v.index(), 1 );
BOOST_TEST_EQ( get<1>(v).v, 2 );
BOOST_TEST_EQ( Z1::instances, 0 );
BOOST_TEST_EQ( Z2::instances, 1 );
v.emplace<0>();
BOOST_TEST_EQ( v.index(), 0 );
BOOST_TEST_EQ( get<0>(v).v, 1 );
BOOST_TEST_EQ( Z1::instances, 1 );
BOOST_TEST_EQ( Z2::instances, 0 );
}
BOOST_TEST_EQ( Z1::instances, 0 );
BOOST_TEST_EQ( Z2::instances, 0 );
return boost::report_errors();
}

View File

@@ -6,6 +6,12 @@
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#if defined( __clang__ ) && defined( __has_warning )
# if __has_warning( "-Wdeprecated-volatile" )
# pragma clang diagnostic ignored "-Wdeprecated-volatile"
# endif
#endif
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>

View File

@@ -6,6 +6,12 @@
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#if defined( __clang__ ) && defined( __has_warning )
# if __has_warning( "-Wdeprecated-volatile" )
# pragma clang diagnostic ignored "-Wdeprecated-volatile"
# endif
#endif
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>

73
test/variant_hash.cpp Normal file
View File

@@ -0,0 +1,73 @@
// Copyright 2020 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER)
# pragma warning( disable: 4244 ) // conversion from int to float, possible loss of data
#endif
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/config/workaround.hpp>
using namespace boost::variant2;
template<template<class...> class Hash, class T1, class T2, class T3> void test()
{
variant<T1, T2, T3> v1( in_place_index_t<0>{} );
std::size_t h1 = Hash<decltype(v1)>()( v1 );
variant<T1, T2, T3> v2( in_place_index_t<1>{} );
std::size_t h2 = Hash<decltype(v2)>()( v2 );
variant<T1, T2, T3> v3( in_place_index_t<2>{} );
std::size_t h3 = Hash<decltype(v3)>()( v3 );
BOOST_TEST_NE( h1, h2 );
BOOST_TEST_NE( h1, h3 );
BOOST_TEST_NE( h2, h3 );
}
template<template<class...> class Hash, class T> void test2()
{
variant<T> v1( 0 );
std::size_t h1 = Hash<decltype(v1)>()( v1 );
variant<T> v2( 1 );
std::size_t h2 = Hash<decltype(v2)>()( v2 );
variant<T> v3( 2 );
std::size_t h3 = Hash<decltype(v3)>()( v3 );
BOOST_TEST_NE( h1, h2 );
BOOST_TEST_NE( h1, h3 );
BOOST_TEST_NE( h2, h3 );
}
struct X {};
int main()
{
test<std::hash, monostate, monostate, monostate>();
test<std::hash, int, int, float>();
test<boost::hash, monostate, monostate, monostate>();
test<boost::hash, int, int, float>();
test2<std::hash, int>();
test2<std::hash, float>();
test2<boost::hash, int>();
test2<boost::hash, float>();
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910) && ( !defined(_LIBCPP_STD_VER) || _LIBCPP_STD_VER > 11 )
BOOST_TEST_TRAIT_FALSE(( detail::is_hash_enabled<X> ));
#endif
return boost::report_errors();
}

View File

@@ -7,11 +7,8 @@
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <utility>
#include <string>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
using namespace boost::variant2;
@@ -108,9 +105,17 @@ int main()
STATIC_ASSERT( v.index() == 4 );
}
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 100200)
// no idea why this fails on g++ 10
#else
{
constexpr variant<int, int, float, float, X, X> v( in_place_index_t<5>{}, 0, 0 );
STATIC_ASSERT( v.index() == 5 );
}
#endif
}

View File

@@ -7,6 +7,8 @@
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
using namespace boost::variant2;
@@ -100,6 +102,12 @@ int main()
STATIC_ASSERT( holds_alternative<X>(v) );
}
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 100200)
// no idea why this fails on g++ 10
#else
{
constexpr variant<int, int, float, float, X> v( in_place_type_t<X>{}, 0, 0 );
@@ -107,4 +115,6 @@ int main()
STATIC_ASSERT( holds_alternative<X>(v) );
}
#endif
}

109
test/variant_many_types.cpp Normal file
View File

@@ -0,0 +1,109 @@
// Copyright 2020 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER)
# pragma warning( disable: 4503 ) // decorated name length exceeded
#endif
#include <boost/variant2/variant.hpp>
#include <boost/mp11.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::mp11;
template<class I> struct X
{
static int const value = I::value;
int v_;
};
template<class I> int const X<I>::value;
template<class I> struct Y
{
static int const value = I::value;
int v_;
Y() = default;
Y( Y const& ) = default;
explicit Y( int v ): v_( v ) {}
Y& operator=( Y const& ) noexcept = default;
Y& operator=( Y&& r ) noexcept
{
v_ = r.v_;
return *this;
}
};
template<class I> int const Y<I>::value;
template<class I> struct Z
{
static int const value = I::value;
int v_;
~Z() {}
};
template<class I> int const Z<I>::value;
template<class V> struct F1
{
template<class T> void operator()( T ) const
{
int const i = T::value;
T t{ i * 2 };
using boost::variant2::get;
{
V v( t );
BOOST_TEST_EQ( v.index(), i );
BOOST_TEST_EQ( get<i>( v ).v_, t.v_ );
BOOST_TEST_EQ( get<T>( v ).v_, t.v_ );
}
{
V const v( t );
BOOST_TEST_EQ( v.index(), i );
BOOST_TEST_EQ( get<i>( v ).v_, t.v_ );
BOOST_TEST_EQ( get<T>( v ).v_, t.v_ );
}
{
V v;
v = t;
BOOST_TEST_EQ( v.index(), i );
BOOST_TEST_EQ( get<i>( v ).v_, t.v_ );
BOOST_TEST_EQ( get<T>( v ).v_, t.v_ );
}
}
};
template<class V> void test()
{
mp_for_each<V>( F1<V>() );
}
int main()
{
int const N = 32;
using V = mp_rename<mp_iota_c<N>, boost::variant2::variant>;
test< mp_transform<X, V> >();
test< mp_transform<Y, V> >();
test< mp_transform<Z, V> >();
return boost::report_errors();
}

103
test/variant_special.cpp Normal file
View File

@@ -0,0 +1,103 @@
// Copyright 2020 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER) && _MSC_VER < 1910
# pragma warning(disable: 4503) // decorated name length exceeded
#endif
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <boost/mp11.hpp>
using namespace boost::mp11;
//
using namespace boost::variant2;
struct D
{
~D() noexcept {}
};
struct CC1
{
CC1( CC1 const& ) {}
};
struct CC2
{
CC2( CC2 const& ) = delete;
};
struct MC1
{
MC1( MC1 && ) {}
};
struct MC2
{
MC2( MC2 && ) = delete;
};
struct CA1
{
CA1& operator=( CA1 const& ) { return *this; }
};
struct CA2
{
CA2& operator=( CA2 const& ) = delete;
};
struct MA1
{
MA1& operator=( MA1 && ) { return *this; }
};
struct MA2
{
MA2& operator=( MA2 && ) = delete;
};
struct test
{
template<class... T> void operator()( mp_list<T...> ) const noexcept
{
using U = mp_inherit<T...>;
#if !BOOST_WORKAROUND( __GNUC__, < 5 )
BOOST_TEST_EQ( std::is_copy_constructible<variant<U>>::value, std::is_copy_constructible<U>::value );
BOOST_TEST_EQ( std::is_nothrow_copy_constructible<variant<U>>::value, std::is_nothrow_copy_constructible<U>::value );
#endif
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
BOOST_TEST_EQ( std::is_move_constructible<variant<U>>::value, std::is_move_constructible<U>::value );
#else
BOOST_TEST_GE( std::is_move_constructible<variant<U>>::value, std::is_move_constructible<U>::value );
#endif
BOOST_TEST_EQ( std::is_nothrow_move_constructible<variant<U>>::value, std::is_nothrow_move_constructible<U>::value );
BOOST_TEST_EQ( std::is_copy_assignable<variant<U>>::value, std::is_copy_constructible<U>::value && std::is_copy_assignable<U>::value );
BOOST_TEST_EQ( std::is_nothrow_copy_assignable<variant<U>>::value, std::is_nothrow_copy_constructible<U>::value && std::is_copy_assignable<U>::value );
BOOST_TEST_EQ( std::is_move_assignable<variant<U>>::value, std::is_move_constructible<U>::value && std::is_move_assignable<U>::value );
BOOST_TEST_EQ( std::is_nothrow_move_assignable<variant<U>>::value, std::is_nothrow_move_constructible<U>::value && std::is_move_assignable<U>::value );
}
};
int main()
{
mp_for_each< mp_power_set< mp_list<D, CC1, CC2, MC1, MC2, CA1, CA2, MA1, MA2> > >( test() );
return boost::report_errors();
}

95
test/variant_trivial.cpp Normal file
View File

@@ -0,0 +1,95 @@
// Copyright 2020 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER) && _MSC_VER < 1910
# pragma warning(disable: 4503) // decorated name length exceeded
#endif
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <boost/mp11.hpp>
using namespace boost::mp11;
//
struct D
{
~D() noexcept {}
};
struct CC1
{
CC1( CC1 const& ) noexcept {}
};
struct CC2
{
CC2( CC2 const& ) = delete;
};
struct MC1
{
MC1( MC1 && ) noexcept {}
};
struct MC2
{
MC2( MC2 && ) = delete;
};
struct CA1
{
CA1& operator=( CA1 const& ) noexcept { return *this; }
};
struct CA2
{
CA2& operator=( CA2 const& ) = delete;
};
struct MA1
{
MA1& operator=( MA1 && ) noexcept { return *this; }
};
struct MA2
{
MA2& operator=( MA2 && ) = delete;
};
using namespace boost::variant2;
namespace v2d = boost::variant2::detail;
struct test
{
template<class... T> void operator()( mp_list<T...> ) const noexcept
{
using U = mp_inherit<T...>;
#if !BOOST_WORKAROUND( __GNUC__, < 5 )
BOOST_TEST_EQ( v2d::is_trivially_copy_constructible<variant<U>>::value, v2d::is_trivially_copy_constructible<U>::value );
BOOST_TEST_EQ( v2d::is_trivially_copy_assignable<variant<U>>::value, std::is_trivially_destructible<U>::value && v2d::is_trivially_copy_constructible<U>::value && v2d::is_trivially_copy_assignable<U>::value );
#endif
BOOST_TEST_EQ( std::is_trivially_destructible<variant<U>>::value, std::is_trivially_destructible<U>::value );
#if !BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION, < 50000)
BOOST_TEST_EQ( v2d::is_trivially_move_constructible<variant<U>>::value, v2d::is_trivially_move_constructible<U>::value );
BOOST_TEST_EQ( v2d::is_trivially_move_assignable<variant<U>>::value, std::is_trivially_destructible<U>::value && v2d::is_trivially_move_constructible<U>::value && v2d::is_trivially_move_assignable<U>::value );
#endif
}
};
int main()
{
mp_for_each< mp_power_set< mp_list<D, CC1, CC2, MC1, MC2, CA1, CA2, MA1, MA2> > >( test() );
return boost::report_errors();
}

View File

@@ -37,6 +37,10 @@ struct F
int main()
{
{
BOOST_TEST_EQ( (visit( []{ return 5; } )), 5 );
}
{
variant<int> v( 1 );

View File

@@ -0,0 +1,57 @@
// Copyright 2017, 2020 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER)
# pragma warning( disable: 4244 ) // conversion from float to int, possible loss of data
#endif
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <utility>
struct X: boost::variant2::variant<int, float>
{
#if BOOST_WORKAROUND( BOOST_MSVC, < 1930 )
template<class T> explicit X( T&& t ): variant( std::forward<T>( t ) ) {};
#else
using variant::variant;
#endif
};
template<class... T> struct Y: boost::variant2::variant<T...>
{
using boost::variant2::variant<T...>::variant;
};
int main()
{
{
X v1( 1 );
X const v2( 3.14f );
BOOST_TEST_EQ( (visit( []( int x1, float x2 ){ return (int)(x1 * 1000) + (int)(x2 * 100); }, v1, v2 )), 1314 );
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, v1, v2 );
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, std::move(v1), std::move(v2) );
}
{
Y<int, float> v1( 1 );
Y<int, float> const v2( 3.14f );
BOOST_TEST_EQ( (visit( []( int x1, float x2 ){ return (int)(x1 * 1000) + (int)(x2 * 100); }, v1, v2 )), 1314 );
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, v1, v2 );
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, std::move(v1), std::move(v2) );
}
return boost::report_errors();
}

98
test/variant_visit_r.cpp Normal file
View File

@@ -0,0 +1,98 @@
// 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
#if defined(_MSC_VER)
# pragma warning( disable: 4244 ) // conversion from float to int, possible loss of data
#endif
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::variant2;
struct F1
{
template<class T1> T1 operator()( T1 t1 ) const
{
return t1;
}
};
struct F2
{
template<class T1, class T2> auto operator()( T1 t1, T2 t2 ) const -> decltype( t1 + t2 )
{
return t1 + t2;
}
};
struct F3
{
template<class T1, class T2, class T3> auto operator()( T1 t1, T2 t2, T3 t3 ) const -> decltype( t1 + t2 + t3 )
{
return t1 + t2 + t3;
}
};
struct F4
{
template<class T1, class T2, class T3, class T4> auto operator()( T1 t1, T2 t2, T3 t3, T4 t4 ) const -> decltype( t1 + t2 + t3 + t4 )
{
return t1 + t2 + t3 + t4;
}
};
int main()
{
{
BOOST_TEST_EQ( (visit<int>( []{ return 3.14f; } )), 3 );
}
{
variant<int, float> v( 1 );
BOOST_TEST_EQ( visit<int>( F1(), v ), 1 );
BOOST_TEST_EQ( visit<float>( F1(), v ), 1.0f );
}
{
variant<int, float> const v( 3.14f );
BOOST_TEST_EQ( visit<int>( F1(), v ), 3 );
BOOST_TEST_EQ( visit<float>( F1(), v ), 3.14f );
}
{
variant<int, float> v1( 1 );
variant<int, float> const v2( 3.14f );
BOOST_TEST_EQ( visit<int>( F2(), v1, v2 ), 4 );
BOOST_TEST_EQ( visit<float>( F2(), v1, v2 ), 1 + 3.14f );
}
{
variant<int, float, double> v1( 1 );
variant<int, float, double> const v2( 3.14f );
variant<int, float, double> v3( 6.28 );
BOOST_TEST_EQ( visit<int>( F3(), v1, v2, v3 ), 10 );
BOOST_TEST_EQ( visit<float>( F3(), v1, v2, v3 ), static_cast<float>( 1 + 3.14f + 6.28 ) );
}
{
variant<int, float, double, char> v1( 1 );
variant<int, float, double, char> const v2( 3.14f );
variant<int, float, double, char> v3( 6.28 );
variant<int, float, double, char> const v4( 'A' );
BOOST_TEST_EQ( visit<int>( F4(), v1, v2, v3, v4 ), 10 + 'A' );
BOOST_TEST_EQ( visit<float>( F4(), v1, v2, v3, v4 ), static_cast<float>( 1 + 3.14f + 6.28 + 'A' ) );
}
return boost::report_errors();
}