Compare commits

...

54 Commits

Author SHA1 Message Date
2ad6fed07a Update revision history 2020-05-10 19:34:12 +03:00
84ea994325 Add specialization for variant_storage_impl<mp_false, ...> 2020-05-09 19:56:27 +03:00
465e5bac3d Add specialization for variant_storage_impl<mp_true, ...> to reduce instantiations 2020-05-09 18:14:12 +03:00
41829b0fb1 test/variant_many_types: cosmetic fixes 2020-05-09 17:55:42 +03:00
b57d75ff80 Merge branch 'develop' into feature/many-types 2020-05-09 14:41:29 +03:00
03019860df Fix gcc-10 version check 2020-05-09 05:10:28 +03:00
8ec4720d2d Merge branch 'feature/clang-10' into feature/gcc-10 2020-05-09 05:09:11 +03:00
75f574fc48 Move warning suppression before the includes 2020-05-09 04:42:27 +03:00
1d79adfca0 Add gcc-10 to Travis 2020-05-09 04:32:11 +03:00
fa92e40b35 Disable failing constexpr tests on g++ 10.1 2020-05-09 04:31:26 +03:00
a403f82691 Disable -Wdeprecated-volatile 2020-05-09 03:57:27 +03:00
a7d0da59ad Add clang-10 to Travis 2020-05-09 03:50:20 +03:00
fa872cb835 test/variant_many_types: add a constructor to Y 2020-05-08 23:23:19 +03:00
93204676f5 Add test/variant_many_types 2020-05-08 22:22:49 +03:00
772ef0d312 Support derived types in visit 2020-05-06 20:11:03 +03:00
f3b3b533aa Remove local mp_power_set implementation, as it's now in mp11 2020-03-20 02:26:01 +02:00
4b60dee4b6 Avoid gcc warning 'base class should be explicitly initialized in copy constructor' 2020-02-01 01:18:40 +02:00
76c67c9b21 Use <warnings>extra instead of all 2020-01-31 23:59:00 +02:00
308bd731a5 Update documentation 2020-01-23 21:17:49 +02:00
719c43316f Disable is_copy_constructible tests on gcc 4.x 2020-01-23 19:13:11 +02:00
d6680df4e5 Add a test case to test/variant_copy_construct 2020-01-23 18:33:39 +02:00
8cf72527a6 Revert incorrect changes in test/variant_trivial 2020-01-23 18:09:01 +02:00
b649a39776 Check std::is_copy_constructible in test/variant_copy_construct 2020-01-23 17:38:03 +02:00
37f6efab5d Fix typo 2020-01-23 17:34:36 +02:00
5259bdd5fc Disable move triviality tests on libstdc++ 4.x 2020-01-23 17:22:45 +02:00
9964e77dd2 Add clang++/trusty to Travis (libstdc++ 4.8) 2020-01-23 15:50:45 +02:00
57ab36bd95 Add test/variant_special 2020-01-23 15:24:32 +02:00
fac5992e45 Add test/variant_trivial 2020-01-23 03:53:05 +02:00
972280e59f Remove commented-out variant_copy_base 2020-01-23 01:08:32 +02:00
ef2ef292b9 The msvc-14.0 workarounds are no longer needed 2020-01-22 20:14:11 +02:00
3b2fb1a48a Split variant_copy_base into separate cc/ca/mc/ma bases; avoids multiple inheritance, which is a penalty in the MS ABI 2020-01-22 19:59:59 +02:00
4f81882bfd Explicitly disable move constructor when needed 2020-01-22 18:30:36 +02:00
17bc06b090 Apply msvc-14.0 workarounds 2020-01-22 17:38:45 +02:00
c4cad3e96a Use an intermediate trivial base for trivial variants 2020-01-22 17:09:15 +02:00
83ff667813 Remove stray compiler: g++ 2020-01-21 02:22:17 +02:00
5e76451843 Use BOOST_INCLUDE_LIBRARIES=variant2 in the CMake install test 2020-01-21 00:43:15 +02:00
c2b5d101eb Update revision history 2020-01-11 15:22:13 +02:00
a92185a86d Add Boost::container_hash to LINK_LIBRARIES 2020-01-11 06:54:23 +02:00
a795f9cf01 Add missing inline 2020-01-11 06:41:21 +02:00
f6e2e78d7d Libc++ doesn't implement a primary std::hash template under C++11 2020-01-11 06:31:45 +02:00
1f05cdfb17 Include <functional>, for g++ trunk (10.0) 2020-01-11 06:06:54 +02:00
1203aa97c0 Add g++ 4.8 to Travis 2020-01-11 05:29:07 +02:00
b3229d48b7 gcc < 7 doesn't like specializing std::hash in a different namespace 2020-01-11 05:27:57 +02:00
be11d94adc Update appveyor.yml 2020-01-11 05:10:28 +02:00
fece11142c Add hashing support 2020-01-11 04:51:30 +02:00
58b4a21deb Add CMake tests 2020-01-09 17:43:54 +02:00
5192a345ab Fix .travis.yml 2019-12-28 22:13:37 +02:00
74e6a04a60 Update .travis.yml 2019-12-28 21:35:20 +02:00
2af66dd815 Add CMake install support 2019-12-28 18:52:32 +02:00
a15364bd81 Update README 2019-09-21 19:12:34 +03:00
12758c076d Fix Travis and Appveyor links 2019-09-21 18:38:55 +03:00
a60f432b64 Add dist: trusty to .travis.yml 2019-06-17 15:07:45 +03:00
bc73c4b822 Fix return code of quick.cpp 2019-06-03 18:48:13 +03:00
566bde5fcc Add CMakeLists.txt 2019-06-03 17:50:13 +03:00
23 changed files with 1322 additions and 196 deletions

View File

@ -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
@ -88,6 +92,17 @@ matrix:
sources:
- ubuntu-toolchain-r-test
- os: linux
dist: bionic
compiler: g++-10
env: TOOLSET=gcc COMPILER=g++-10 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- g++-10
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-8
env: UBSAN=1 TOOLSET=gcc COMPILER=g++-8 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold
@ -98,6 +113,11 @@ matrix:
sources:
- ubuntu-toolchain-r-test
- os: linux
dist: trusty
compiler: clang++
env: DIST=trusty TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: linux
compiler: clang++-3.5
env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=11,14,1z
@ -108,7 +128,6 @@ matrix:
- libstdc++-4.9-dev
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.5
- os: linux
compiler: clang++-3.6
@ -119,7 +138,6 @@ matrix:
- clang-3.6
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.6
- os: linux
compiler: clang++-3.7
@ -130,7 +148,6 @@ matrix:
- clang-3.7
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.7
- os: linux
compiler: clang++-3.8
@ -141,7 +158,6 @@ matrix:
- clang-3.8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.8
- os: linux
compiler: clang++-3.9
@ -152,7 +168,6 @@ matrix:
- clang-3.9
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.9
- os: linux
compiler: clang++-4.0
@ -163,7 +178,6 @@ matrix:
- clang-4.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
- os: linux
compiler: clang++-5.0
@ -174,7 +188,6 @@ matrix:
- clang-5.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-5.0
- os: linux
compiler: clang++-6.0
@ -185,7 +198,6 @@ matrix:
- clang-6.0
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-6.0
- os: linux
compiler: clang++-7
@ -196,7 +208,7 @@ matrix:
- clang-7
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-7
- llvm-toolchain-xenial-7
- os: linux
compiler: clang++-8
@ -207,20 +219,47 @@ matrix:
- clang-8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-8
- llvm-toolchain-xenial-8
- os: linux
compiler: clang++-6.0
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1
dist: xenial
compiler: clang++-9
env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-6.0
- clang-9
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-6.0
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
dist: xenial
compiler: clang++-10
env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-10
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
compiler: clang++-8
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1
addons:
apt:
packages:
- clang-8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-8
- os: linux
dist: trusty
compiler: clang++-libc++
env: TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=11,14,1z
addons:
@ -229,6 +268,7 @@ matrix:
- libc++-dev
- os: linux
dist: trusty
compiler: clang++-libc++
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=11,14,1z UBSAN_OPTIONS=print_stacktrace=1
addons:
@ -240,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
View 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()

View File

@ -2,15 +2,14 @@
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/doc/libs/master/libs/variant2/)
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/nVUNKX).
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:
@ -19,4 +18,4 @@ Supported compilers:
* Visual Studio 2015, 2017, 2019
Tested on [Travis](https://travis-ci.org/boostorg/variant2/) and
[Appveyor](https://ci.appveyor.com/project/pdimov/variant2/).
[Appveyor](https://ci.appveyor.com/project/pdimov/variant2-fkab9).

View File

@ -1,4 +1,4 @@
# Copyright 2016-2018 Peter Dimov
# Copyright 2016-2020 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
@ -21,6 +21,14 @@ environment:
TOOLSET: msvc-14.1
ADDRMD: 32,64
CXXSTD: 14,17
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: clang-win
ADDRMD: 64
CXXSTD: 14,17
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: msvc-14.2
ADDRMD: 32,64
CXXSTD: 14,17
install:
- set BOOST_BRANCH=develop
@ -28,8 +36,6 @@ install:
- cd ..
- git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
- cd boost-root
- git submodule update --init tools/build
- git submodule update --init libs/config
- git submodule update --init tools/boostdep
- xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\variant2\
- python tools/boostdep/depinst/depinst.py variant2
@ -41,4 +47,4 @@ build: off
test_script:
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
- b2 libs/variant2/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release
- b2 -j3 libs/variant2/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release

View File

@ -1,5 +1,5 @@
////
Copyright 2019 Peter Dimov
Copyright 2019, 2020 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
@ -11,6 +11,17 @@ http://www.boost.org/LICENSE_1_0.txt
# 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

View File

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

View File

@ -21,5 +21,5 @@ This implementation only depends on Boost.Config and Boost.Mp11.
* Clang 3.5 or later with `-std=c++11` or above
* Visual Studio 2015, 2017, 2019
Tested on https://travis-ci.org/pdimov/variant2/[Travis] and
https://ci.appveyor.com/project/pdimov/variant2/[Appveyor].
Tested on https://travis-ci.org/boostorg/variant2/[Travis] and
https://ci.appveyor.com/project/pdimov/variant2-fkab9[Appveyor].

View File

@ -18,12 +18,14 @@
#endif
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/cstdint.hpp>
#include <cstddef>
#include <type_traits>
#include <exception>
#include <cassert>
#include <initializer_list>
#include <utility>
#include <functional> // std::hash
//
@ -547,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...>
{
@ -588,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;
@ -1050,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:
@ -1076,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,
@ -1175,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,
@ -1598,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;
@ -1637,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>...>>;
@ -1666,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 )
@ -1708,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
@ -1733,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
@ -1759,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)... );
@ -1785,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

11
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,11 @@
# Copyright 2018, 2019 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
if(HAVE_BOOST_TEST)
boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::variant2 Boost::core Boost::container_hash)
endif()

View File

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

View File

@ -0,0 +1,17 @@
# Copyright 2018, 2019 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.16)
project(cmake_install_test LANGUAGES CXX)
find_package(boost_variant2 REQUIRED)
add_executable(quick ../quick.cpp)
target_link_libraries(quick Boost::variant2)
enable_testing()
add_test(quick quick)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)

View File

@ -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
View 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;
}

View File

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

View File

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

View File

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

73
test/variant_hash.cpp Normal file
View File

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

View File

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

View File

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

109
test/variant_many_types.cpp Normal file
View File

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

103
test/variant_special.cpp Normal file
View File

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

95
test/variant_trivial.cpp Normal file
View File

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

View File

@ -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();
}