mirror of
https://github.com/boostorg/variant2.git
synced 2025-12-24 07:38:06 +01:00
Compare commits
72 Commits
feature/st
...
feature/ma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ad6fed07a | ||
|
|
84ea994325 | ||
|
|
465e5bac3d | ||
|
|
41829b0fb1 | ||
|
|
b57d75ff80 | ||
|
|
03019860df | ||
|
|
8ec4720d2d | ||
|
|
75f574fc48 | ||
|
|
1d79adfca0 | ||
|
|
fa92e40b35 | ||
|
|
a403f82691 | ||
|
|
a7d0da59ad | ||
|
|
fa872cb835 | ||
|
|
93204676f5 | ||
|
|
772ef0d312 | ||
|
|
f3b3b533aa | ||
|
|
4b60dee4b6 | ||
|
|
76c67c9b21 | ||
|
|
308bd731a5 | ||
|
|
719c43316f | ||
|
|
d6680df4e5 | ||
|
|
8cf72527a6 | ||
|
|
b649a39776 | ||
|
|
37f6efab5d | ||
|
|
5259bdd5fc | ||
|
|
9964e77dd2 | ||
|
|
57ab36bd95 | ||
|
|
fac5992e45 | ||
|
|
972280e59f | ||
|
|
ef2ef292b9 | ||
|
|
3b2fb1a48a | ||
|
|
4f81882bfd | ||
|
|
17bc06b090 | ||
|
|
c4cad3e96a | ||
|
|
83ff667813 | ||
|
|
5e76451843 | ||
|
|
c2b5d101eb | ||
|
|
a92185a86d | ||
|
|
a795f9cf01 | ||
|
|
f6e2e78d7d | ||
|
|
1f05cdfb17 | ||
|
|
1203aa97c0 | ||
|
|
b3229d48b7 | ||
|
|
be11d94adc | ||
|
|
fece11142c | ||
|
|
58b4a21deb | ||
|
|
5192a345ab | ||
|
|
74e6a04a60 | ||
|
|
2af66dd815 | ||
|
|
a15364bd81 | ||
|
|
12758c076d | ||
|
|
a60f432b64 | ||
|
|
bc73c4b822 | ||
|
|
566bde5fcc | ||
|
|
2e831fbdb2 | ||
|
|
2738f081cd | ||
|
|
f5d9662946 | ||
|
|
adeb970be6 | ||
|
|
6b617ae3a8 | ||
|
|
04f655e76a | ||
|
|
c4f7f2d63a | ||
|
|
504abbe8eb | ||
|
|
8cb1789167 | ||
|
|
69b25cb42a | ||
|
|
6b3a2b2b4d | ||
|
|
2d990f774a | ||
|
|
a083667a96 | ||
|
|
e686dab3ea | ||
|
|
3041fff85c | ||
|
|
cacd99d69d | ||
|
|
64ea067c79 | ||
|
|
475ad691d6 |
135
.travis.yml
135
.travis.yml
@@ -4,9 +4,7 @@
|
||||
|
||||
language: cpp
|
||||
|
||||
sudo: false
|
||||
|
||||
python: "2.7"
|
||||
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
|
||||
@@ -78,6 +82,27 @@ matrix:
|
||||
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++-8
|
||||
env: UBSAN=1 TOOLSET=gcc COMPILER=g++-8 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold
|
||||
@@ -88,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
|
||||
@@ -98,7 +128,6 @@ matrix:
|
||||
- libstdc++-4.9-dev
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.5
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-3.6
|
||||
@@ -109,7 +138,6 @@ matrix:
|
||||
- clang-3.6
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.6
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-3.7
|
||||
@@ -120,7 +148,6 @@ matrix:
|
||||
- clang-3.7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.7
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-3.8
|
||||
@@ -131,7 +158,6 @@ matrix:
|
||||
- clang-3.8
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.8
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-3.9
|
||||
@@ -142,7 +168,6 @@ matrix:
|
||||
- clang-3.9
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.9
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-4.0
|
||||
@@ -153,7 +178,6 @@ matrix:
|
||||
- clang-4.0
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-4.0
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-5.0
|
||||
@@ -164,7 +188,6 @@ matrix:
|
||||
- clang-5.0
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-5.0
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-6.0
|
||||
@@ -175,7 +198,6 @@ matrix:
|
||||
- clang-6.0
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-6.0
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-7
|
||||
@@ -186,20 +208,58 @@ matrix:
|
||||
- clang-7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-7
|
||||
- llvm-toolchain-xenial-7
|
||||
|
||||
- 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
|
||||
compiler: clang++-8
|
||||
env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=11,14,17,2a
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-6.0
|
||||
- clang-8
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-6.0
|
||||
- llvm-toolchain-xenial-8
|
||||
|
||||
- os: linux
|
||||
dist: xenial
|
||||
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/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:
|
||||
@@ -208,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:
|
||||
@@ -219,13 +280,47 @@ 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
|
||||
env: CMAKE_TEST=1
|
||||
script:
|
||||
- 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:
|
||||
- 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
|
||||
|
||||
31
CMakeLists.txt
Normal file
31
CMakeLists.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
# Copyright 2018, 2019 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...3.16)
|
||||
|
||||
project(boost_variant2 VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
add_library(boost_variant2 INTERFACE)
|
||||
add_library(Boost::variant2 ALIAS boost_variant2)
|
||||
|
||||
target_include_directories(boost_variant2 INTERFACE include)
|
||||
|
||||
target_link_libraries(boost_variant2
|
||||
INTERFACE
|
||||
Boost::config
|
||||
Boost::mp11
|
||||
)
|
||||
|
||||
if(BOOST_SUPERPROJECT_VERSION)
|
||||
|
||||
include(BoostInstall)
|
||||
boost_install(TARGETS boost_variant2 HEADER_DIRECTORY include/)
|
||||
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
|
||||
add_subdirectory(test)
|
||||
|
||||
endif()
|
||||
61
README.md
61
README.md
@@ -1,64 +1,21 @@
|
||||
# variant2
|
||||
|
||||
This repository contains a never-valueless C++11/14/17 implementation of
|
||||
[std::variant](http://en.cppreference.com/w/cpp/utility/variant) in
|
||||
[variant.hpp](include/boost/variant2/variant.hpp) and an implementation of
|
||||
`expected<T, E...>` in [expected.hpp](include/boost/variant2/expected.hpp)
|
||||
that is an extended version of `expected<T, E>` as proposed in
|
||||
[P0323R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0323r1.pdf)
|
||||
and the subsequent
|
||||
[D0323R2](https://github.com/viboes/std-make/blob/master/doc/proposal/expected/d0323r2.md).
|
||||
This repository contains a never-valueless, strong guarantee, C++11/14/17
|
||||
implementation of [std::variant](http://en.cppreference.com/w/cpp/utility/variant).
|
||||
See [the documentation](https://www.boost.org/libs/variant2)
|
||||
for more information.
|
||||
|
||||
The code requires [Boost.Mp11](https://github.com/boostorg/mp11) and
|
||||
Boost.Config.
|
||||
|
||||
The repository is intended to be placed into the `libs/variant2` directory of
|
||||
a Boost clone or release, but the header `variant.hpp` will also work
|
||||
[standalone](https://godbolt.org/z/CTZztA).
|
||||
The library is part of Boost, starting from release 1.71, but the header
|
||||
`variant.hpp` will also work [standalone](https://godbolt.org/z/nVUNKX).
|
||||
|
||||
Supported compilers:
|
||||
|
||||
* g++ 4.8 or later with `-std=c++11` or above
|
||||
* clang++ 3.5 or later with `-std=c++11` or above
|
||||
* Visual Studio 2015, 2017
|
||||
* Visual Studio 2015, 2017, 2019
|
||||
|
||||
Tested on [Travis](https://travis-ci.org/pdimov/variant2/) and
|
||||
[Appveyor](https://ci.appveyor.com/project/pdimov/variant2/).
|
||||
|
||||
## variant.hpp
|
||||
|
||||
The class `boost::variant2::variant<T...>` is an almost conforming
|
||||
implementation of `std::variant` with the following differences:
|
||||
|
||||
* A converting constructor from, e.g. `variant<int, float>` to
|
||||
`variant<float, double, int>` is provided as an extension;
|
||||
* The reverse operation, going from `variant<float, double, int>` to
|
||||
`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 trivial when all contained types are trivial.
|
||||
|
||||
To avoid going into a valueless-by-exception state, this implementation falls
|
||||
back to using double storage unless
|
||||
|
||||
* one of the alternatives is the type `monostate`,
|
||||
* one of the alternatives has a nonthrowing default constructor, or
|
||||
* all the contained types are nothrow move constructible.
|
||||
|
||||
If the first two bullets don't hold, but the third does, the variant uses
|
||||
single storage, but `emplace` constructs a temporary and moves it into place
|
||||
if the construction of the object can throw. In case this is undesirable, one
|
||||
can force `emplace` into always constructing in-place by adding `monostate` as
|
||||
one of the alternatives.
|
||||
|
||||
## expected.hpp
|
||||
|
||||
The class `boost::variant2::expected<T, E...>` represents the return type of
|
||||
an operation that may potentially fail. It contains either the expected result
|
||||
of type `T`, or a reason for the failure, of one of the error types in `E...`.
|
||||
Internally, this is stored as `variant<T, E...>`.
|
||||
|
||||
See [its documentation](doc/expected.md) for more information.
|
||||
|
||||
Note that, while `variant` is production quality, `expected` is still a work
|
||||
in progress and has no test suite yet.
|
||||
Tested on [Travis](https://travis-ci.org/boostorg/variant2/) and
|
||||
[Appveyor](https://ci.appveyor.com/project/pdimov/variant2-fkab9).
|
||||
|
||||
14
appveyor.yml
14
appveyor.yml
@@ -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
|
||||
|
||||
1
doc/.gitignore
vendored
1
doc/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
/pdf/
|
||||
/html/
|
||||
|
||||
305
doc/expected.md
305
doc/expected.md
@@ -1,305 +0,0 @@
|
||||
# expected<T, E...>
|
||||
|
||||
## Description
|
||||
|
||||
The class `expected<T, E...>` presented here is an extended version of `expected<T, E>` as
|
||||
proposed in [P0323R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0323r1.pdf)
|
||||
and the subsequent [D0323R2](https://github.com/viboes/std-make/blob/master/doc/proposal/expected/d0323r2.md).
|
||||
|
||||
The main difference is that this class takes more than one error type, which makes it more
|
||||
flexible. One example of a type of the `expected` family, [`outcome<T>`](https://ned14.github.io/boost.outcome/),
|
||||
on failure can store either an error of type `std::error_code`, or an exception in the form of `std::exception_ptr`.
|
||||
This can be represented naturally in this implementation via `expected<T, std::error_code, std::exception_ptr>`.
|
||||
|
||||
In addition, libraries would generally differ in their choice of error types. It would be a
|
||||
common need in practice of having to combine the results of calling two different libraries,
|
||||
each with its own error type. Library 1 may use `lib1::error`:
|
||||
|
||||
namespace lib1
|
||||
{
|
||||
|
||||
enum class error
|
||||
{
|
||||
division_by_zero,
|
||||
other_error
|
||||
};
|
||||
|
||||
expected<double, error> div( double x, double y );
|
||||
|
||||
} // namespace lib1
|
||||
|
||||
while Library 2 might define its own `lib2::error`:
|
||||
|
||||
namespace lib2
|
||||
{
|
||||
|
||||
enum class error
|
||||
{
|
||||
division_by_zero,
|
||||
negative_logarithm
|
||||
};
|
||||
|
||||
expected<double, error> log( double x );
|
||||
|
||||
} // namespace lib2
|
||||
|
||||
In this proposal, combining the results of `lib1::div` and `lib2::log` can be achieved via
|
||||
simple composition:
|
||||
|
||||
expected<double, lib1::error, lib2::error> log_div_mul( double x, double y, double m )
|
||||
{
|
||||
auto r1 = lib1::div( x, y );
|
||||
if( !r1 ) return r1.unexpected();
|
||||
|
||||
auto r2 = lib2::log( r1.value() );
|
||||
if( !r2 ) return r2.unexpected();
|
||||
|
||||
return m * r2.value();
|
||||
}
|
||||
|
||||
An alternative approach that requires more effort is also supported:
|
||||
|
||||
enum class common_error
|
||||
{
|
||||
division_by_zero,
|
||||
negative_logarithm,
|
||||
other_error,
|
||||
unknown_error
|
||||
};
|
||||
|
||||
common_error make_common_error( lib1::error e );
|
||||
common_error make_common_error( lib2::error e );
|
||||
|
||||
expected<double, common_error> log_div_mul2( double x, double y, double m )
|
||||
{
|
||||
static const auto rm = []( auto x ) { return make_common_error(x); };
|
||||
|
||||
auto r1 = lib1::div( x, y ).remap_errors( rm );
|
||||
if( !r1 ) return r1.unexpected();
|
||||
|
||||
auto r2 = lib2::log( r1.value() ).remap_errors( rm );
|
||||
if( !r2 ) return r2.unexpected();
|
||||
|
||||
return m * r2.value();
|
||||
}
|
||||
|
||||
`std::error_code` is a very good choice for a common error type, and it's supported
|
||||
natively by the overload of `.remap_errors()` that takes no arguments, which uses
|
||||
calls to `make_error_code` to translate the errors.
|
||||
|
||||
When an attempt to access the value via `r.value()` is made and an error is present,
|
||||
an exception is thrown. By default, this exception is of type `bad_expected_access<E>`,
|
||||
as in D0323R2, but there are two differences. First, `bad_expected_access<E>` objects
|
||||
derive from a common base `bad_expected_access<void>` so that they can be caught at
|
||||
points where the set of possible `E` is unknown.
|
||||
|
||||
Second, the thrown exception can be customized. The implementation calls
|
||||
`throw_on_unexpected(e)` unqualified, where `e` is the error object, and the user can
|
||||
define such a function in the namespace of the type of `e`. Two specialized overloads
|
||||
of `throw_on_unexpected` are provided, one for `std::error_code`, which throws the
|
||||
corresponding `std::system_error`, and one for `std::exception_ptr`, which rethrows
|
||||
the exception stored in it.
|
||||
|
||||
For example, `lib1` from above may customize the exceptions associated with `lib1::error`
|
||||
via the following:
|
||||
|
||||
namespace lib1
|
||||
{
|
||||
|
||||
enum class error
|
||||
{
|
||||
division_by_zero,
|
||||
other_error
|
||||
};
|
||||
|
||||
class exception: public std::exception
|
||||
{
|
||||
private:
|
||||
|
||||
error e_;
|
||||
|
||||
public:
|
||||
|
||||
explicit exception( error e ): e_( e ) {}
|
||||
virtual const char * what() const noexcept;
|
||||
};
|
||||
|
||||
void throw_on_unexpected( error e )
|
||||
{
|
||||
throw exception( e );
|
||||
}
|
||||
|
||||
} // namespace lib1
|
||||
|
||||
In this implementation, `unexpected_type<E...>` has been called `unexpected_<T...>` and is
|
||||
an alias for `variant<T...>`. It is unfortunately not possible to use the name `unexpected<T...>`,
|
||||
because a function `std::unexpected` already exists.
|
||||
|
||||
The `make_...` helper functions have been omitted as unnecessary; class template argument deduction
|
||||
as in `expected{ 1.0 }` or `unexpected_{ lib1::division_by_zero }` suffices.
|
||||
|
||||
Other functions have also been dropped as unnecessary, not providing sufficient value, dangerous, or
|
||||
a combination of the three, although the decision of what to include isn't final at this point. The aim
|
||||
is to produce a minimal interface that still covers the use cases.
|
||||
|
||||
`expected<T, E1...>` can be converted to `expected<T, E2...>` if all error types in `E1...` are
|
||||
also in `E2...`. This allows composition as in the example above. Whether value convertibility ought
|
||||
to also be supported is an open question.
|
||||
|
||||
A single monadic operation ("bind") is supported in the form of `operator>>`, allowing
|
||||
|
||||
auto log_div_mul3( double x, double y, double m )
|
||||
{
|
||||
return lib1::div( x, y ) >> [&]( auto && r1 ) {
|
||||
|
||||
return lib2::log( r1 ) >> [&]( auto && r2 ) -> expected<double, lib1::error, lib2::error> {
|
||||
|
||||
return m * r2;
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
as well as the more concise in this example, although limited in utility for real world scenarios,
|
||||
|
||||
auto log_div_mul3( double x, double y, double m )
|
||||
{
|
||||
return lib1::div( x, y ) >> std::bind<expected<double, lib1::error, lib2::error>>( lib2::log, _1 ) >> m * _1;
|
||||
}
|
||||
|
||||
The more traditional name `then` was also a candidate for this operation, but `operator>>` has two advantages;
|
||||
it avoids the inevitable naming debates and does not require parentheses around the continuation lambda.
|
||||
|
||||
## Synopsis
|
||||
|
||||
// unexpected_
|
||||
|
||||
template<class... E> using unexpected_ = variant<E...>;
|
||||
|
||||
// bad_expected_access
|
||||
|
||||
template<class E = void> class bad_expected_access;
|
||||
|
||||
template<> class bad_expected_access<void>: public std::exception
|
||||
{
|
||||
public:
|
||||
|
||||
bad_expected_access() noexcept;
|
||||
char const * what() const noexcept;
|
||||
};
|
||||
|
||||
template<class E> class bad_expected_access: public bad_expected_access<void>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit bad_expected_access( E const& e );
|
||||
E error() const;
|
||||
};
|
||||
|
||||
// throw_on_unexpected
|
||||
|
||||
template<class E> void throw_on_unexpected( E const& e );
|
||||
void throw_on_unexpected( std::error_code const& e );
|
||||
void throw_on_unexpected( std::exception_ptr const& e );
|
||||
|
||||
// expected
|
||||
|
||||
template<class T, class... E> class expected
|
||||
{
|
||||
public:
|
||||
|
||||
// value constructors
|
||||
|
||||
constexpr expected() noexcept( /*see below*/ );
|
||||
|
||||
constexpr expected( T const& t ) noexcept( /*see below*/ );
|
||||
constexpr expected( T&& t ) noexcept( /*see below*/ );
|
||||
|
||||
// unexpected constructor
|
||||
|
||||
template<class... E2>
|
||||
constexpr expected( unexpected_<E2...> const& x );
|
||||
|
||||
template<class... E2>
|
||||
constexpr expected( unexpected_<E2...>&& x );
|
||||
|
||||
// conversion constructor
|
||||
|
||||
template<class... E2>
|
||||
constexpr expected( expected<T, E2...> const& x );
|
||||
|
||||
template<class... E2>
|
||||
constexpr expected( expected<T, E2...>&& x );
|
||||
|
||||
// emplace
|
||||
|
||||
template<class... A> void emplace( A&&... a );
|
||||
template<class V, class... A> void emplace( std::initializer_list<V> il, A&&... a );
|
||||
|
||||
// swap
|
||||
|
||||
void swap( expected& r ) noexcept( /*see below*/ );
|
||||
|
||||
// value queries
|
||||
|
||||
constexpr bool has_value() const noexcept;
|
||||
constexpr explicit operator bool() const noexcept;
|
||||
|
||||
// checked value access
|
||||
|
||||
constexpr T& value() &;
|
||||
constexpr T const& value() const&;
|
||||
constexpr T&& value() &&;
|
||||
constexpr T const&& value() const&&;
|
||||
|
||||
// unchecked value access
|
||||
|
||||
T* operator->() noexcept;
|
||||
T const* operator->() const noexcept;
|
||||
|
||||
T& operator*() & noexcept;
|
||||
T const& operator*() const & noexcept;
|
||||
T&& operator*() && noexcept;
|
||||
T const&& operator*() const && noexcept;
|
||||
|
||||
// error queries
|
||||
|
||||
template<class E2> constexpr bool has_error() const noexcept;
|
||||
constexpr bool has_error() const noexcept;
|
||||
|
||||
// error access
|
||||
|
||||
unexpected_<E...> unexpected() const;
|
||||
|
||||
template<class E2> constexpr E2 error() const noexcept;
|
||||
constexpr /*see below*/ error() const noexcept;
|
||||
|
||||
// error mapping
|
||||
|
||||
template<class F> /*see below*/ remap_errors( F&& f ) const;
|
||||
expected<T, std::error_code> remap_errors() const;
|
||||
|
||||
// then
|
||||
|
||||
template<class F> /*see below*/ operator>>( F&& f ) const;
|
||||
};
|
||||
|
||||
template<class T, class... E>
|
||||
inline constexpr bool operator==( expected<T, E...> const& x1, expected<T, E...> const& x2 );
|
||||
|
||||
template<class T, class... E>
|
||||
inline constexpr bool operator!=( expected<T, E...> const& x1, expected<T, E...> const& x2 );
|
||||
|
||||
template<class T, class... E>
|
||||
inline void swap( expected<T, E...>& x1, expected<T, E...>& x2 ) noexcept( /*see below*/ );
|
||||
|
||||
// is_expected
|
||||
|
||||
template<class T> struct is_expected;
|
||||
|
||||
} // namespace variant2
|
||||
} // namespace boost
|
||||
|
||||
## Reference
|
||||
|
||||
...
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,9 @@ Peter Dimov
|
||||
:leveloffset: +1
|
||||
|
||||
include::variant2/overview.adoc[]
|
||||
include::variant2/changelog.adoc[]
|
||||
include::variant2/design.adoc[]
|
||||
include::variant2/implementation.adoc[]
|
||||
include::variant2/reference.adoc[]
|
||||
include::variant2/copyright.adoc[]
|
||||
|
||||
|
||||
29
doc/variant2/changelog.adoc
Normal file
29
doc/variant2/changelog.adoc
Normal file
@@ -0,0 +1,29 @@
|
||||
////
|
||||
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
|
||||
:idprefix: changelog_
|
||||
|
||||
## Changes in 1.74.0
|
||||
|
||||
* Improve compilation performance for many (hundreds of) alternatives.
|
||||
|
||||
## 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
|
||||
changed to provide the strong exception safety guarantee,
|
||||
instead of basic. `expected` has been removed.
|
||||
185
doc/variant2/design.adoc
Normal file
185
doc/variant2/design.adoc
Normal file
@@ -0,0 +1,185 @@
|
||||
////
|
||||
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
|
||||
////
|
||||
|
||||
[#design]
|
||||
# Design
|
||||
:idprefix: design_
|
||||
|
||||
## Features
|
||||
|
||||
This `variant` implementation has two distinguishing features:
|
||||
|
||||
* It's never "valueless", that is, `variant<T1, T2, ..., Tn>` has an
|
||||
invariant that it always contains a valid value of one of the types
|
||||
`T1`, `T2`, ..., `Tn`.
|
||||
* It provides the strong exception safety guarantee on assignment and
|
||||
`emplace`.
|
||||
|
||||
This is achieved with the use of double storage, unless all of the
|
||||
contained types have a non-throwing move constructor.
|
||||
|
||||
## Rationale
|
||||
|
||||
### Never Valueless
|
||||
|
||||
It makes intuitive sense that `variant<X, Y, Z>` can hold only values
|
||||
of type `X`, type `Y`, or type `Z`, and nothing else.
|
||||
|
||||
If we think of `variant` as an extension of `union`, since a `union`
|
||||
has a state called "no active member", an argument can be made that a
|
||||
`variant<X, Y, Z>` should also have such an additional state, holding
|
||||
none of `X`, `Y`, `Z`.
|
||||
|
||||
This however makes `variant` less convenient in practice and less useful
|
||||
as a building block. If we really need a variable that only holds `X`,
|
||||
`Y`, or `Z`, the additional empty state creates complications that need
|
||||
to be worked around. And in the case where we do need this additional
|
||||
empty state, we can just use `variant<empty, X, Y, Z>`, with a suitable
|
||||
`struct empty {};`.
|
||||
|
||||
From a pure design perspective, the case for no additional empty state is
|
||||
solid. Implementation considerations, however, argue otherwise.
|
||||
|
||||
When we replace the current value of the `variant` (of, say, type `X`) with
|
||||
another (of type `Y`), since the new value needs to occupy the same storage
|
||||
as the old one, we need to destroy the old `X` first, then construct a new
|
||||
`Y` in its place. But since this is {cpp}, the construction can fail with an
|
||||
exception. At this point the `variant` is in the "has no active member"
|
||||
state that we've agreed it cannot be in.
|
||||
|
||||
This is a legitimate problem, and it is this problem that makes having
|
||||
an empty/valueless state so appealing. We just leave the `variant` empty on
|
||||
exception and we're done.
|
||||
|
||||
As explained, though, this is undesirable from a design perspective as it
|
||||
makes the component less useful and less elegant.
|
||||
|
||||
There are several ways around the issue. The most straightforward one is to
|
||||
just disallow types whose construction can throw. Since we can always create
|
||||
a temporary value first, then use the move constructor to initialize the one
|
||||
in the `variant`, it's enough to require a nonthrowing move constructor,
|
||||
rather than all constructors to be nonthrowing.
|
||||
|
||||
Unfortunately, under at least one popular standard library implementation,
|
||||
node based containers such as `std::list` and `std::map` have a potentially
|
||||
throwing move constructor. Disallowing `variant<X, std::map<Y, Z>>` is hardly
|
||||
practical, so the exceptional case cannot be avoided.
|
||||
|
||||
On exception, we could also construct some other value, leaving the `variant`
|
||||
valid; but in the general case, that construction can also throw. If one of
|
||||
the types has a nonthrowing default constructor, we can use it; but if not,
|
||||
we can't.
|
||||
|
||||
The approach Boost.Variant takes here is to allocate a temporary copy of
|
||||
the value on the heap. On exception, a pointer to that temporary copy can be
|
||||
stored into the `variant`. Pointer operations don't throw.
|
||||
|
||||
Another option is to use double buffering. If our `variant` occupies twice
|
||||
the storage, we can construct the new value in the unused half, then, once
|
||||
the construction succeeds, destroy the old value in the other half.
|
||||
|
||||
When `std::variant` was standardized, none of those approaches was deemed
|
||||
palatable, as all of them either introduce overhead or are too restrictive
|
||||
with respect to the types a `variant` can contain. So as a compromise,
|
||||
`std::variant` took a way that can (noncharitably) be described as "having
|
||||
your cake and eating it too."
|
||||
|
||||
Since the described exceptional situation is relatively rare, `std::variant`
|
||||
has a special case, called "valueless", into which it goes on exception,
|
||||
but the interface acknowledges its existence as little as possible, allowing
|
||||
users to pretend that it doesn't exist.
|
||||
|
||||
This is, arguably, not that bad from a practical point of view, but it leaves
|
||||
many of us wanting. Rare states that "never" occur are undertested and when
|
||||
that "never" actually happens, it's usually in the most inconvenient of times.
|
||||
|
||||
This implementation does not follow `std::variant`; it statically guarantees
|
||||
that `variant` is never in a valueless state. The function
|
||||
`valueless_by_exception` is provided for compatibility, but it always returns
|
||||
`false`.
|
||||
|
||||
Instead, if the contained types are such that it's not possible to avoid an
|
||||
exceptional situation when changing the contained value, double storage is
|
||||
used.
|
||||
|
||||
### Strong Exception Safety
|
||||
|
||||
The initial submission only provided the basic exception safety guarantee.
|
||||
If an attempt to change the contained value (via assignment or `emplace`)
|
||||
failed with an exception, and a type with a nonthrowing default constructor
|
||||
existed among the alternatives, a value of that type was created into the
|
||||
`variant`. The upside of this decision was that double storage was needed
|
||||
less frequently.
|
||||
|
||||
The reviewers were fairly united in hating it. Constructing a random type
|
||||
was deemed too unpredictable and not complying with the spirit of the
|
||||
basic guarantee. The default constructor of the chosen type, even if
|
||||
nonthrowing, may still have undesirable side effects. Or, if not that, a
|
||||
value of that type may have special significance for the surrounding code.
|
||||
Therefore, some argued, the `variant` should either remain with its
|
||||
old value, or transition into the new one, without synthesizing other
|
||||
states.
|
||||
|
||||
At the other side of the spectrum, there were those who considered double
|
||||
storage unacceptable. But they considered it unacceptable in principle,
|
||||
regardless of the frequency with which it was used.
|
||||
|
||||
As a result, providing the strong exception safety guarantee on assignment
|
||||
and `emplace` was declared an acceptance condition.
|
||||
|
||||
In retrospect, this was the right decision. The reason the strong guarantee
|
||||
is generally not provided is because it doesn't compose. When `X` and `Y`
|
||||
provide the basic guarantee on assignment, so does `struct { X x; Y y; };`.
|
||||
Similarly, when `X` and `Y` have nonthrowing assignments, so does the
|
||||
`struct`. But this doesn't hold for the strong guarantee.
|
||||
|
||||
The usual practice is to provide the basic guarantee on assignment and
|
||||
let the user synthesize a "strong" assignment out of either a nonthrowing
|
||||
`swap` or a nonthrowing move assignment. That is, given `x1` and `x2` of
|
||||
type `X`, instead of the "basic" `x1 = x2;`, use either `X(x2).swap(x1);`
|
||||
or `x1 = X(x2);`.
|
||||
|
||||
Nearly all types provide a nonthrowing `swap` or a nonthrowing move
|
||||
assignment, so this works well. Nearly all, except `variant`, which in the
|
||||
general case has neither a nonthrowing `swap` nor a nonthrowing move
|
||||
assignment. If `variant` does not provide the strong guarantee itself, it's
|
||||
impossible for the user to synthesize it.
|
||||
|
||||
So it should, and so it does.
|
||||
|
||||
## Differences with std::variant
|
||||
|
||||
The main differences between this implementation and `std::variant` are:
|
||||
|
||||
* No valueless-by-exception state: `valueless_by_exception()` always
|
||||
returns `false`.
|
||||
* Strong exception safety guarantee on assignment and `emplace`.
|
||||
* `emplace` first constructs the new value and then destroys the old one;
|
||||
in the single storage case, this translates to constructing a temporary
|
||||
and then moving it into place.
|
||||
* A converting constructor from, e.g. `variant<int, float>` to
|
||||
`variant<float, double, int>` is provided as an extension.
|
||||
* The reverse operation, going from `variant<float, double, int>` to
|
||||
`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.)
|
||||
* The {cpp}20 additions and changes to `std::variant` have not yet been
|
||||
implemented.
|
||||
|
||||
## Differences with Boost.Variant
|
||||
|
||||
This library is API compatible with `std::variant`. As such, its interface
|
||||
is different from Boost.Variant's. For example, visitation is performed via
|
||||
`visit` instead of `apply_visitor`.
|
||||
|
||||
Recursive variants are not supported.
|
||||
|
||||
Double storage is used instead of temporary heap backup. This `variant` is
|
||||
always "stack-based", it never allocates, and never throws `bad_alloc` on
|
||||
its own.
|
||||
25
doc/variant2/implementation.adoc
Normal file
25
doc/variant2/implementation.adoc
Normal file
@@ -0,0 +1,25 @@
|
||||
////
|
||||
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
|
||||
////
|
||||
|
||||
[#implementation]
|
||||
# Implementation
|
||||
:idprefix: implementation_
|
||||
|
||||
## Dependencies
|
||||
|
||||
This implementation only depends on Boost.Config and Boost.Mp11.
|
||||
|
||||
## Supported Compilers
|
||||
|
||||
* GCC 4.8 or later with `-std=c++11` or above
|
||||
* Clang 3.5 or later with `-std=c++11` or above
|
||||
* Visual Studio 2015, 2017, 2019
|
||||
|
||||
Tested on https://travis-ci.org/boostorg/variant2/[Travis] and
|
||||
https://ci.appveyor.com/project/pdimov/variant2-fkab9[Appveyor].
|
||||
@@ -247,6 +247,9 @@ public:
|
||||
} // namespace boost
|
||||
```
|
||||
|
||||
In the descriptions that follow, let `i` be in the range `[0, sizeof...(T))`,
|
||||
and `Ti` be the `i`-th type in `T...`.
|
||||
|
||||
#### Constructors
|
||||
|
||||
```
|
||||
@@ -707,6 +710,8 @@ template<size_t I, class... T>
|
||||
+
|
||||
Effects: :: If `v.index()` is `I`, returns a reference to the object stored in
|
||||
the variant. Otherwise, throws `bad_variant_access`.
|
||||
Remarks: :: These functions do not participate in overload resolution
|
||||
unless `I` < `sizeof...(T)`.
|
||||
|
||||
```
|
||||
template<class U, class... T>
|
||||
@@ -747,9 +752,10 @@ template<size_t I, class... T>
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Requires: :: `I < sizeof...(U)`. Otherwise, the program is ill-formed.
|
||||
Effects: :: A pointer to the value stored in the variant, if
|
||||
`v != nullptr && v\->index() == I`. Otherwise, `nullptr`.
|
||||
Remarks: :: These functions do not participate in overload resolution
|
||||
unless `I` < `sizeof...(T)`.
|
||||
|
||||
```
|
||||
template<class U, class... T>
|
||||
@@ -778,7 +784,7 @@ template<class... T>
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns: :: `v.index() == w.index && get<I>(v) == get<I>(w)`, where `I`
|
||||
Returns: :: `v.index() == w.index() && get<I>(v) == get<I>(w)`, where `I`
|
||||
is `v.index()`.
|
||||
|
||||
```
|
||||
@@ -797,7 +803,7 @@ template<class... T>
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns: :: `v.index() < w.index || (v.index() == w.index && get<I>(v) < get<I>(w))`,
|
||||
Returns: :: `v.index() < w.index() || (v.index() == w.index() && get<I>(v) < get<I>(w))`,
|
||||
where `I` is `v.index()`.
|
||||
|
||||
```
|
||||
@@ -816,7 +822,7 @@ template<class... T>
|
||||
[none]
|
||||
* {blank}
|
||||
+
|
||||
Returns: :: `v.index() < w.index || (v.index() == w.index && get<I>(v) \<= get<I>(w))`,
|
||||
Returns: :: `v.index() < w.index() || (v.index() == w.index() && get<I>(v) \<= get<I>(w))`,
|
||||
where `I` is `v.index()`.
|
||||
|
||||
```
|
||||
|
||||
@@ -1,446 +0,0 @@
|
||||
#ifndef BOOST_VARIANT2_EXPECTED_HPP_INCLUDED
|
||||
#define BOOST_VARIANT2_EXPECTED_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
|
||||
|
||||
#ifndef BOOST_VARIANT2_VARIANT_HPP_INCLUDED
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#endif
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <cassert>
|
||||
|
||||
//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace variant2
|
||||
{
|
||||
|
||||
// unexpected_
|
||||
|
||||
template<class... E> using unexpected_ = variant<E...>;
|
||||
|
||||
// bad_expected_access
|
||||
|
||||
template<class E = void> class bad_expected_access;
|
||||
|
||||
template<> class bad_expected_access<void>: public std::exception
|
||||
{
|
||||
private:
|
||||
|
||||
std::string msg_;
|
||||
|
||||
public:
|
||||
|
||||
bad_expected_access() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
explicit bad_expected_access( std::string&& msg ) noexcept: msg_( std::move(msg) ) // extension
|
||||
{
|
||||
}
|
||||
|
||||
char const * what() const noexcept
|
||||
{
|
||||
return msg_.empty()? "bad_expected_access<>": msg_.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class E, class En = std::enable_if_t<!std::is_enum<E>::value>> std::string add_value( E const& /*e*/ )
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
template<class E, class E1 = void, class E2 = std::enable_if_t<std::is_enum<E>::value>> std::string add_value( E const& e )
|
||||
{
|
||||
return ": " + std::to_string( static_cast<int>(e) );
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class E> class bad_expected_access: public bad_expected_access<void>
|
||||
{
|
||||
private:
|
||||
|
||||
E e_;
|
||||
|
||||
public:
|
||||
|
||||
explicit bad_expected_access( E const& e )
|
||||
: bad_expected_access<void>( "bad_expected_access<" + boost::core::demangle( typeid(E).name() ) + ">" + variant2::detail::add_value( e ) ), e_( e )
|
||||
{
|
||||
}
|
||||
|
||||
E error() const
|
||||
{
|
||||
return e_;
|
||||
}
|
||||
};
|
||||
|
||||
// throw_on_unexpected
|
||||
|
||||
template<class E> void throw_on_unexpected( E const& /*e*/ )
|
||||
{
|
||||
}
|
||||
|
||||
void throw_on_unexpected( std::error_code const & e )
|
||||
{
|
||||
throw std::system_error( e );
|
||||
}
|
||||
|
||||
void throw_on_unexpected( std::exception_ptr const & e )
|
||||
{
|
||||
if( e )
|
||||
{
|
||||
std::rethrow_exception( e );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_expected_access<>( "bad_expected_access<>: null exception_ptr" );
|
||||
}
|
||||
}
|
||||
|
||||
// expected
|
||||
|
||||
template<class T, class... E> class expected;
|
||||
|
||||
template<class T> struct is_expected: std::false_type {};
|
||||
template<class T, class... E> struct is_expected<expected<T, E...>>: std::true_type {};
|
||||
|
||||
template<class T, class... E> class expected
|
||||
{
|
||||
private:
|
||||
|
||||
variant<T, E...> v_;
|
||||
|
||||
private:
|
||||
|
||||
void _bad_access() const
|
||||
{
|
||||
mp_with_index<mp_size<expected>>( v_.index(), [&]( auto I )
|
||||
{
|
||||
if( I == 0 )
|
||||
{
|
||||
throw bad_expected_access<>( "bad_expected_access<>: value present on error request" );
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const & e = get<I>(v_);
|
||||
|
||||
throw_on_unexpected( e );
|
||||
throw bad_expected_access<std::decay_t<decltype(e)>>( e );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// value constructors
|
||||
|
||||
constexpr expected() noexcept( std::is_nothrow_default_constructible<T>::value )
|
||||
{
|
||||
}
|
||||
|
||||
constexpr expected( T const& t ) noexcept( std::is_nothrow_copy_constructible<T>::value ): v_( in_place_index<0>, t )
|
||||
{
|
||||
}
|
||||
|
||||
constexpr expected( T && t ) noexcept( std::is_nothrow_move_constructible<T>::value ): v_( in_place_index<0>, std::move(t) )
|
||||
{
|
||||
}
|
||||
|
||||
// template<class U> constexpr expected( U && u ); where U in E...?
|
||||
|
||||
// in-place constructor?
|
||||
|
||||
// unexpected constructor
|
||||
|
||||
template<class... E2,
|
||||
class En = mp_if<mp_all<std::is_copy_constructible<E2>..., mp_contains<mp_list<E...>, E2>...>, void>>
|
||||
constexpr expected( unexpected_<E2...> const & x ): v_( x )
|
||||
{
|
||||
}
|
||||
|
||||
template<class... E2,
|
||||
class En = mp_if<mp_all<std::is_move_constructible<E2>..., mp_contains<mp_list<E...>, E2>...>, void>>
|
||||
constexpr expected( unexpected_<E2...> && x ): v_( std::move(x) )
|
||||
{
|
||||
}
|
||||
|
||||
// conversion constructor
|
||||
|
||||
template<class... E2,
|
||||
class En = mp_if<mp_all<std::is_copy_constructible<E2>..., mp_contains<mp_list<E...>, E2>...>, void>>
|
||||
constexpr expected( expected<T, E2...> const & x ): v_( x.v_ )
|
||||
{
|
||||
}
|
||||
|
||||
template<class... E2,
|
||||
class En = mp_if<mp_all<std::is_move_constructible<E2>..., mp_contains<mp_list<E...>, E2>...>, void>>
|
||||
constexpr expected( expected<T, E2...> && x ): v_( std::move(x.v_) )
|
||||
{
|
||||
}
|
||||
|
||||
// emplace
|
||||
|
||||
template<class... A> void emplace( A&&... a )
|
||||
{
|
||||
v_.emplace( std::forward<A>(a)... );
|
||||
}
|
||||
|
||||
template<class V, class... A> void emplace( std::initializer_list<V> il, A&&... a )
|
||||
{
|
||||
v_.emplace( il, std::forward<A>(a)... );
|
||||
}
|
||||
|
||||
// swap
|
||||
|
||||
void swap( expected & r ) noexcept( noexcept( v_.swap( r.v_ ) ) )
|
||||
{
|
||||
v_.swap( r.v_ );
|
||||
}
|
||||
|
||||
// value queries
|
||||
|
||||
constexpr bool has_value() const noexcept
|
||||
{
|
||||
return v_.index() == 0;
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const noexcept
|
||||
{
|
||||
return v_.index() == 0;
|
||||
}
|
||||
|
||||
// checked value access
|
||||
|
||||
constexpr T& value() &
|
||||
{
|
||||
if( !has_value() )
|
||||
{
|
||||
_bad_access();
|
||||
}
|
||||
|
||||
return *get_if<0>(&v_);
|
||||
}
|
||||
|
||||
constexpr T const& value() const&
|
||||
{
|
||||
if( !has_value() )
|
||||
{
|
||||
_bad_access();
|
||||
}
|
||||
|
||||
return *get_if<0>(&v_);
|
||||
}
|
||||
|
||||
constexpr T&& value() &&
|
||||
{
|
||||
return std::move( value() );
|
||||
}
|
||||
|
||||
constexpr T const&& value() const&&
|
||||
{
|
||||
return std::move( value() );
|
||||
}
|
||||
|
||||
// unchecked value access
|
||||
|
||||
T* operator->() noexcept
|
||||
{
|
||||
return get_if<0>(&v_);
|
||||
}
|
||||
|
||||
T const* operator->() const noexcept
|
||||
{
|
||||
return get_if<0>(&v_);
|
||||
}
|
||||
|
||||
T& operator*() & noexcept
|
||||
{
|
||||
T* p = get_if<0>(&v_);
|
||||
|
||||
assert( p != 0 );
|
||||
|
||||
return *p;
|
||||
}
|
||||
|
||||
T const& operator*() const & noexcept
|
||||
{
|
||||
T const* p = get_if<0>(&v_);
|
||||
|
||||
assert( p != 0 );
|
||||
|
||||
return *p;
|
||||
}
|
||||
|
||||
T&& operator*() && noexcept
|
||||
{
|
||||
return std::move(**this);
|
||||
}
|
||||
|
||||
T const&& operator*() const && noexcept
|
||||
{
|
||||
return std::move(**this);
|
||||
}
|
||||
|
||||
// error queries
|
||||
|
||||
template<class E2> constexpr bool has_error() const noexcept
|
||||
{
|
||||
using I = mp_find<expected, E2>;
|
||||
return v_.index() == I::value;
|
||||
}
|
||||
|
||||
constexpr bool has_error() const noexcept
|
||||
{
|
||||
static_assert( sizeof...(E) == 1, "has_error() is only valid when there is a single E" );
|
||||
return has_error<mp_first<expected>>();
|
||||
}
|
||||
|
||||
// error access
|
||||
|
||||
unexpected_<E...> unexpected() const
|
||||
{
|
||||
if( has_value() )
|
||||
{
|
||||
_bad_access();
|
||||
}
|
||||
|
||||
return v_.template subset<E...>();
|
||||
}
|
||||
|
||||
template<class E2> constexpr E2 error() const noexcept
|
||||
{
|
||||
using I = mp_find<expected, E2>;
|
||||
|
||||
if( v_.index() != I::value )
|
||||
{
|
||||
_bad_access();
|
||||
}
|
||||
|
||||
return get<I>( v_ );
|
||||
}
|
||||
|
||||
constexpr mp_first<expected> error() const noexcept
|
||||
{
|
||||
static_assert( sizeof...(E) == 1, "error() is only valid when there is a single E" );
|
||||
return error<mp_first<expected>>();
|
||||
}
|
||||
|
||||
// error mapping
|
||||
|
||||
private:
|
||||
|
||||
template<class F> struct Qret
|
||||
{
|
||||
template<class... A> using fn = decltype( std::declval<F>()( std::declval<A>()... ) );
|
||||
};
|
||||
|
||||
template<class F> using remapped = mp_append<expected<T>, mp_unique<mp_transform_q<Qret<F>, mp_list<E...>>>>;
|
||||
|
||||
template<class R, std::size_t I, class F, class V> static R _remap_error( mp_size_t<I>, F && f, V && v )
|
||||
{
|
||||
// return R( std::forward<F>(f)( std::forward<V>(v) ) );
|
||||
|
||||
auto e = std::forward<F>(f)( std::forward<V>(v) );
|
||||
|
||||
return unexpected_<decltype(e)>{ e };
|
||||
}
|
||||
|
||||
template<class R, class F, class V> static R _remap_error( mp_size_t<0>, F && /*f*/, V && v )
|
||||
{
|
||||
return R( std::forward<V>(v) );
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<class F> remapped<F> remap_errors( F && f ) const
|
||||
{
|
||||
using R = remapped<F>;
|
||||
|
||||
return mp_with_index<mp_size<expected>>( v_.index(), [&]( auto I ) {
|
||||
|
||||
return this->_remap_error<R>( I, f, get<I>(v_) );
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
expected<T, std::error_code> remap_errors() const
|
||||
{
|
||||
using R = expected<T, std::error_code>;
|
||||
|
||||
auto f = []( auto const& e ){ return make_error_code(e); };
|
||||
|
||||
return mp_with_index<mp_size<expected>>( v_.index(), [&]( auto I ) {
|
||||
|
||||
return this->_remap_error<R>( I, f, get<I>(v_) );
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// then
|
||||
|
||||
private:
|
||||
|
||||
template<class F, class U> using then_result_ = decltype( std::declval<F>()( std::declval<U>() ) );
|
||||
|
||||
template<class F, class U, class R = then_result_<F, U>> using then_result = mp_if<is_expected<R>, R, expected<R, E...>>;
|
||||
|
||||
public:
|
||||
|
||||
template<class F> then_result<F, T const&> then( F && f ) const
|
||||
{
|
||||
if( has_value() )
|
||||
{
|
||||
return std::forward<F>(f)( **this );
|
||||
}
|
||||
else
|
||||
{
|
||||
return unexpected();
|
||||
}
|
||||
}
|
||||
|
||||
template<class F> then_result<F, T const&> operator>>( F && f ) const
|
||||
{
|
||||
if( has_value() )
|
||||
{
|
||||
return std::forward<F>(f)( **this );
|
||||
}
|
||||
else
|
||||
{
|
||||
return unexpected();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class T, class... E> inline constexpr bool operator==( expected<T, E...> const & x1, expected<T, E...> const & x2 )
|
||||
{
|
||||
return x1.v_ == x2.v_;
|
||||
}
|
||||
|
||||
template<class T, class... E> inline constexpr bool operator!=( expected<T, E...> const & x1, expected<T, E...> const & x2 )
|
||||
{
|
||||
return x1.v_ != x2.v_;
|
||||
}
|
||||
|
||||
template<class T, class... E> inline void swap( expected<T, E...> & x1, expected<T, E...> & x2 ) noexcept( noexcept( x1.swap( x2 ) ) )
|
||||
{
|
||||
x1.swap( x2 );
|
||||
}
|
||||
|
||||
} // namespace variant2
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_VARIANT2_EXPECTED_HPP_INCLUDED
|
||||
@@ -18,17 +18,26 @@
|
||||
#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
|
||||
|
||||
//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
#ifdef BOOST_NO_EXCEPTIONS
|
||||
|
||||
BOOST_NORETURN void throw_exception( std::exception const & e ); // user defined
|
||||
|
||||
#endif
|
||||
|
||||
namespace variant2
|
||||
{
|
||||
|
||||
@@ -48,6 +57,24 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_NORETURN inline void throw_bad_variant_access()
|
||||
{
|
||||
#ifdef BOOST_NO_EXCEPTIONS
|
||||
|
||||
boost::throw_exception( bad_variant_access() );
|
||||
|
||||
#else
|
||||
|
||||
throw bad_variant_access();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// monostate
|
||||
|
||||
struct monostate
|
||||
@@ -283,7 +310,7 @@ template<class U, class... T> constexpr bool holds_alternative( variant<T...> co
|
||||
template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T...>>& get(variant<T...>& v)
|
||||
{
|
||||
static_assert( I < sizeof...(T), "Index out of bounds" );
|
||||
return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp11::mp_size_t<I>() );
|
||||
return ( v.index() != I? detail::throw_bad_variant_access(): (void)0 ), v._get_impl( mp11::mp_size_t<I>() );
|
||||
}
|
||||
|
||||
template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T...>>&& get(variant<T...>&& v)
|
||||
@@ -292,11 +319,11 @@ template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
|
||||
|
||||
return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp11::mp_size_t<I>() ) );
|
||||
return ( v.index() != I? detail::throw_bad_variant_access(): (void)0 ), std::move( v._get_impl( mp11::mp_size_t<I>() ) );
|
||||
|
||||
#else
|
||||
|
||||
if( v.index() != I ) throw bad_variant_access();
|
||||
if( v.index() != I ) detail::throw_bad_variant_access();
|
||||
return std::move( v._get_impl( mp11::mp_size_t<I>() ) );
|
||||
|
||||
#endif
|
||||
@@ -305,7 +332,7 @@ template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T
|
||||
template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T...>> const& get(variant<T...> const& v)
|
||||
{
|
||||
static_assert( I < sizeof...(T), "Index out of bounds" );
|
||||
return (void)( v.index() != I? throw bad_variant_access(): 0 ), v._get_impl( mp11::mp_size_t<I>() );
|
||||
return ( v.index() != I? detail::throw_bad_variant_access(): (void)0 ), v._get_impl( mp11::mp_size_t<I>() );
|
||||
}
|
||||
|
||||
template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T...>> const&& get(variant<T...> const&& v)
|
||||
@@ -314,11 +341,11 @@ template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
|
||||
|
||||
return (void)( v.index() != I? throw bad_variant_access(): 0 ), std::move( v._get_impl( mp11::mp_size_t<I>() ) );
|
||||
return ( v.index() != I? detail::throw_bad_variant_access(): (void)0 ), std::move( v._get_impl( mp11::mp_size_t<I>() ) );
|
||||
|
||||
#else
|
||||
|
||||
if( v.index() != I ) throw bad_variant_access();
|
||||
if( v.index() != I ) detail::throw_bad_variant_access();
|
||||
return std::move( v._get_impl( mp11::mp_size_t<I>() ) );
|
||||
|
||||
#endif
|
||||
@@ -363,7 +390,7 @@ template<class U, class... T> constexpr U& get(variant<T...>& v)
|
||||
|
||||
using I = mp11::mp_find<variant<T...>, U>;
|
||||
|
||||
return (void)( v.index() != I::value? throw bad_variant_access(): 0 ), v._get_impl( I() );
|
||||
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), v._get_impl( I() );
|
||||
}
|
||||
|
||||
template<class U, class... T> constexpr U&& get(variant<T...>&& v)
|
||||
@@ -374,11 +401,11 @@ template<class U, class... T> constexpr U&& get(variant<T...>&& v)
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
|
||||
|
||||
return (void)( v.index() != I::value? throw bad_variant_access(): 0 ), std::move( v._get_impl( I() ) );
|
||||
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), std::move( v._get_impl( I() ) );
|
||||
|
||||
#else
|
||||
|
||||
if( v.index() != I::value ) throw bad_variant_access();
|
||||
if( v.index() != I::value ) detail::throw_bad_variant_access();
|
||||
return std::move( v._get_impl( I() ) );
|
||||
|
||||
#endif
|
||||
@@ -390,7 +417,7 @@ template<class U, class... T> constexpr U const& get(variant<T...> const& v)
|
||||
|
||||
using I = mp11::mp_find<variant<T...>, U>;
|
||||
|
||||
return (void)( v.index() != I::value? throw bad_variant_access(): 0 ), v._get_impl( I() );
|
||||
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), v._get_impl( I() );
|
||||
}
|
||||
|
||||
template<class U, class... T> constexpr U const&& get(variant<T...> const&& v)
|
||||
@@ -401,11 +428,11 @@ template<class U, class... T> constexpr U const&& get(variant<T...> const&& v)
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
|
||||
|
||||
return (void)( v.index() != I::value? throw bad_variant_access(): 0 ), std::move( v._get_impl( I() ) );
|
||||
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), std::move( v._get_impl( I() ) );
|
||||
|
||||
#else
|
||||
|
||||
if( v.index() != I::value ) throw bad_variant_access();
|
||||
if( v.index() != I::value ) detail::throw_bad_variant_access();
|
||||
return std::move( v._get_impl( I() ) );
|
||||
|
||||
#endif
|
||||
@@ -522,6 +549,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...>
|
||||
{
|
||||
@@ -563,6 +672,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;
|
||||
@@ -1025,20 +1233,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<std::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<std::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:
|
||||
|
||||
@@ -1051,71 +1556,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,
|
||||
@@ -1150,75 +1592,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,
|
||||
@@ -1310,11 +1686,6 @@ public:
|
||||
|
||||
// private accessors
|
||||
|
||||
constexpr int _real_index() const noexcept
|
||||
{
|
||||
return this->ix_;
|
||||
}
|
||||
|
||||
using variant_base::_get_impl;
|
||||
|
||||
// converting constructors (extension)
|
||||
@@ -1378,7 +1749,7 @@ private:
|
||||
|
||||
template<class... U, class V> static variant<U...> _subset_impl( mp11::mp_size_t<sizeof...(U)>, V && /*v*/ )
|
||||
{
|
||||
throw bad_variant_access();
|
||||
detail::throw_bad_variant_access();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1578,6 +1949,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;
|
||||
@@ -1617,7 +2007,7 @@ 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>...>>;
|
||||
|
||||
@@ -1646,7 +2036,7 @@ template<class F, class V1> struct visit_L1
|
||||
|
||||
template<class F, class V1> constexpr auto visit( F&& f, V1&& v1 ) -> detail::Vret<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<F, V1>{ std::forward<F>(f), std::forward<V1>(v1) } );
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) || BOOST_WORKAROUND( BOOST_MSVC, < 1920 )
|
||||
@@ -1688,7 +2078,7 @@ template<class F, class V1, class V2> struct visit_L2
|
||||
|
||||
template<class F, class V1, class V2> constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> detail::Vret<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<F, V1, V2>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2) } );
|
||||
}
|
||||
|
||||
namespace detail
|
||||
@@ -1713,7 +2103,7 @@ template<class F, class V1, class V2, class V3> struct visit_L3
|
||||
|
||||
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>
|
||||
{
|
||||
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<F, V1, V2, V3>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3) } );
|
||||
}
|
||||
|
||||
namespace detail
|
||||
@@ -1739,14 +2129,14 @@ template<class F, class V1, class V2, class V3, class V4> struct visit_L4
|
||||
|
||||
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>
|
||||
{
|
||||
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<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...>
|
||||
{
|
||||
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)... );
|
||||
@@ -1765,9 +2155,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
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to
|
||||
<a href="doc/html/mp11.html">doc/html/variant2.html</a>.
|
||||
<a href="doc/html/variant2.html">doc/html/variant2.html</a>.
|
||||
</body>
|
||||
</html>
|
||||
<!--
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"maintainers": [
|
||||
"Peter Dimov <pdimov -at- pdimov.com>"
|
||||
],
|
||||
"description": "A never-valueless implementation of std::variant.",
|
||||
"description": "A never-valueless, strong guarantee implementation of std::variant.",
|
||||
"category": [
|
||||
"Containers", "Data"
|
||||
]
|
||||
|
||||
11
test/CMakeLists.txt
Normal file
11
test/CMakeLists.txt
Normal 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()
|
||||
41
test/Jamfile
41
test/Jamfile
@@ -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 ] ;
|
||||
@@ -89,3 +91,26 @@ run variant_convert_construct_throw.cpp ;
|
||||
|
||||
run variant_copy_assign_throw.cpp ;
|
||||
run variant_move_assign_throw.cpp ;
|
||||
|
||||
local NX =
|
||||
<exception-handling>off
|
||||
<toolset>msvc:<cxxflags>/wd4530
|
||||
<toolset>msvc:<cxxflags>/wd4577
|
||||
;
|
||||
|
||||
run variant_get_by_index.cpp throw_exception.cpp : : : $(NX) : variant_get_by_index_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) <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 ;
|
||||
|
||||
17
test/cmake_install_test/CMakeLists.txt
Normal file
17
test/cmake_install_test/CMakeLists.txt
Normal 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>)
|
||||
19
test/cmake_subdir_test/CMakeLists.txt
Normal file
19
test/cmake_subdir_test/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
# 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_subdir_test LANGUAGES CXX)
|
||||
|
||||
add_subdirectory(../.. boostorg/variant2)
|
||||
add_subdirectory(../../../config boostorg/config)
|
||||
add_subdirectory(../../../mp11 boostorg/mp11)
|
||||
|
||||
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>)
|
||||
15
test/quick.cpp
Normal file
15
test/quick.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
// Copyright 2019 Peter Dimov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/variant2/variant.hpp>
|
||||
|
||||
using namespace boost::variant2;
|
||||
|
||||
int main()
|
||||
{
|
||||
variant<float, int> v( 2 );
|
||||
return get<1>( v ) == 2? 0: 1;
|
||||
}
|
||||
20
test/throw_exception.cpp
Normal file
20
test/throw_exception.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
// Copyright 2019 Peter Dimov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <exception>
|
||||
#include <cstdio>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
void throw_exception( std::exception const & e )
|
||||
{
|
||||
std::fprintf( stderr, "Exception: %s\n", e.what() );
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
@@ -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>>));
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
73
test/variant_hash.cpp
Normal 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();
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
109
test/variant_many_types.cpp
Normal 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
103
test/variant_special.cpp
Normal 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
95
test/variant_trivial.cpp
Normal 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();
|
||||
}
|
||||
57
test/variant_visit_derived.cpp
Normal file
57
test/variant_visit_derived.cpp
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user