Compare commits

...

45 Commits

Author SHA1 Message Date
5c0274a76e glob headers 2022-07-05 10:48:50 +02:00
d34658f4c8 Document operator<< for monostate 2022-01-31 19:19:49 +02:00
5e2bce1baa Add operator<< for monostate 2022-01-31 17:55:26 +02:00
573ef77382 Move unsigned ix_ after the elements to avoid need to adjust rdi (closes #30) 2021-12-09 21:28:35 +02:00
f6cad272d4 Add msvc-14.0 to GHA 2021-12-09 19:59:01 +02:00
3fc7540733 Only define operator<< when all contained types are streamable (refs #31) 2021-12-09 18:39:03 +02:00
e4b4b3f02b Extend msvc-14.2 workaround to 14.3 2021-10-29 02:18:23 +03:00
44d38c4111 Enable syntax highlighting 2021-10-28 23:23:13 +03:00
1ebfb3b689 Add msvc-14.3 to ci.yml 2021-10-28 23:22:20 +03:00
8af1fbde8e Update cmake_subdir_test/CMakeLists.txt 2021-09-21 14:52:38 +03:00
26ce33597d Regenerate CMakeLists.txt 2021-09-21 14:45:20 +03:00
c89713b978 Add CMake tests to ci.yml 2021-09-21 14:31:47 +03:00
10c441c8d7 Update appveyor.yml 2021-09-15 15:11:54 +03:00
09ec260780 Document operator<< 2021-09-15 03:53:13 +03:00
2da13befd7 Work around mysterious errors with gcc, msvc-14.1, and clang-cl 2021-09-15 03:28:29 +03:00
e668c099ce Add operator<< for variant 2021-09-15 02:51:11 +03:00
aebcb9792d Update documentation of visit_by_index 2021-09-15 02:00:33 +03:00
8fd9f830a9 Add proper type deduction to visit_by_index 2021-09-15 01:30:09 +03:00
ed4bebff3d Document visit_by_index 2021-09-14 21:32:57 +03:00
ad06c9b923 Add visit_by_index 2021-09-14 21:06:01 +03:00
de4eb8b6d2 Update README.md 2021-09-11 19:47:34 +03:00
4d69db1441 Extend g++-10 workarounds to 11 2021-09-11 19:23:39 +03:00
095d9770c4 Update ci.yml 2021-09-11 18:36:43 +03:00
cca476fbbc Update documentation 2021-09-11 18:29:17 +03:00
c76af4d3cf Update README.md 2021-09-11 18:26:28 +03:00
1af7b165cf BOOST_VARIANT2_CX14_ASSERT must be empty under C++11 2021-09-11 18:22:46 +03:00
49bff72be0 Define and use a helper macro BOOST_VARIANT2_CX14_ASSERT in constexpr functions 2021-09-11 18:11:17 +03:00
59780ba08e Only assert when C++14 2021-09-11 18:00:29 +03:00
edd70cfd66 Update ci.yml 2021-09-11 17:43:05 +03:00
86c2782dff Update documentation 2021-09-11 17:39:55 +03:00
dce8174550 Make unsafe_get public 2021-09-11 17:29:21 +03:00
9d40bc80f1 Use BOOST_ASSERT instead of assert 2021-09-11 17:23:29 +03:00
be6ddf9fdc Add boost/variant2.hpp 2021-09-11 17:19:09 +03:00
4153a535a0 Update .github/workflows 2021-04-19 20:37:12 +03:00
f374ad68a3 Add -DBUILD_TESTING=ON to .yml files; it's not default anymore 2021-03-19 04:18:08 +02:00
3bc9a57c9b Merge branch 'feature/issue-26' into develop 2021-03-13 18:23:39 +02:00
3ca95a65df Use boost::hash in hash_value, not std::hash (closes #27) 2021-03-13 05:08:03 +02:00
ae1f72671e Add test for types supported by boost::hash, but not by std::hash 2021-03-13 04:50:01 +02:00
a2dab8c7d3 Refactor detail::hash_value_L 2021-03-13 04:10:41 +02:00
f39a71ed2f Merge branch 'feature/issue-26-nofix' into feature/issue-26 2021-03-13 01:09:46 +02:00
06dde96400 Merge branch 'develop' into feature/issue-26-nofix 2021-03-13 01:09:17 +02:00
8be0a4a5fe Update copyright 2021-03-12 23:42:32 +02:00
90cda5339f Disable U&& constructor for derived types 2021-03-12 23:40:14 +02:00
afb0aafd64 Change clangs to bionic 2021-03-12 20:18:24 +02:00
f586dc8848 Add test for inherited constructors (refs #26) 2021-03-12 20:15:09 +02:00
23 changed files with 851 additions and 142 deletions

View File

@ -19,18 +19,15 @@ jobs:
include:
- toolset: gcc-4.8
cxxstd: "03,11"
os: ubuntu-16.04
os: ubuntu-18.04
install: g++-4.8
- toolset: gcc-4.9
cxxstd: "03,11"
os: ubuntu-16.04
install: g++-4.9
- toolset: gcc-5
cxxstd: "03,11,14,1z"
os: ubuntu-16.04
os: ubuntu-18.04
install: g++-5
- toolset: gcc-6
cxxstd: "03,11,14,1z"
os: ubuntu-16.04
os: ubuntu-18.04
install: g++-6
- toolset: gcc-7
cxxstd: "03,11,14,17"
@ -38,51 +35,38 @@ jobs:
- toolset: gcc-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
install: g++-8
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
os: ubuntu-20.04
- toolset: gcc-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
- toolset: clang
compiler: clang++-3.5
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.5
- toolset: clang
compiler: clang++-3.6
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.6
- toolset: clang
compiler: clang++-3.7
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.7
- toolset: clang
compiler: clang++-3.8
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.8
os: ubuntu-20.04
install: g++-10
- toolset: gcc-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: g++-11
- toolset: clang
compiler: clang++-3.9
cxxstd: "03,11,14"
os: ubuntu-16.04
os: ubuntu-18.04
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "03,11,14"
os: ubuntu-16.04
os: ubuntu-18.04
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "03,11,14,1z"
os: ubuntu-16.04
os: ubuntu-18.04
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
cxxstd: "03,11,14,17"
os: ubuntu-18.04
install: clang-6.0
- toolset: clang
compiler: clang++-7
cxxstd: "03,11,14,17"
@ -90,16 +74,29 @@ jobs:
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "03,11,14,17,2a"
cxxstd: "03,11,14,17"
os: ubuntu-20.04
install: clang-8
- toolset: clang
compiler: clang++-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: clang-9
- toolset: clang
compiler: clang++-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: clang-10
- toolset: clang
compiler: clang++-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: clang-11
- toolset: clang
compiler: clang++-12
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: clang-12
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-10.15
@ -150,6 +147,10 @@ jobs:
fail-fast: false
matrix:
include:
- toolset: msvc-14.0
cxxstd: "14"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.1
cxxstd: "14,17,latest"
addrmd: 32,64
@ -158,6 +159,10 @@ jobs:
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.3
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2022
- toolset: gcc
cxxstd: "03,11,14,17,2a"
addrmd: 64
@ -195,3 +200,159 @@ jobs:
run: |
cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release
posix-cmake-subdir:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: macos-10.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Use library with add_subdirectory
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test
mkdir __build__ && cd __build__
cmake ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-install:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: macos-10.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local ..
- name: Install
run: |
cd ../boost-root/__build__
cmake --build . --target install
- name: Use the installed library
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-test:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
- os: macos-10.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON ..
- name: Build tests
run: |
cd ../boost-root/__build__
cmake --build . --target tests
- name: Run tests
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error

View File

@ -1,4 +1,4 @@
# Copyright 2016-2019 Peter Dimov
# Copyright 2016-2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
@ -165,6 +165,7 @@ matrix:
- ubuntu-toolchain-r-test
- os: linux
dist: bionic
compiler: clang++-5.0
env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=11,14,1z
addons:
@ -175,6 +176,7 @@ matrix:
- ubuntu-toolchain-r-test
- os: linux
dist: bionic
compiler: clang++-6.0
env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=11,14,17
addons:
@ -185,6 +187,7 @@ matrix:
- ubuntu-toolchain-r-test
- os: linux
dist: bionic
compiler: clang++-7
env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=11,14,17,2a
addons:
@ -193,9 +196,10 @@ matrix:
- clang-7
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-7
- llvm-toolchain-bionic-7
- os: linux
dist: bionic
compiler: clang++-8
env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=11,14,17,2a
addons:
@ -204,10 +208,10 @@ matrix:
- clang-8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-8
- llvm-toolchain-bionic-8
- os: linux
dist: xenial
dist: bionic
compiler: clang++-9
env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=11,14,17,2a
addons:
@ -216,11 +220,11 @@ matrix:
- clang-9
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
dist: xenial
dist: bionic
compiler: clang++-10
env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=11,14,17,2a
addons:
@ -229,20 +233,33 @@ matrix:
- clang-10
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main'
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
dist: xenial
dist: bionic
compiler: clang++-11
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-11 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1
env: TOOLSET=clang COMPILER=clang++-11 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-11
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-11 main'
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
dist: bionic
compiler: clang++-12
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-12 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1
addons:
apt:
packages:
- clang-12
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-12 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
@ -271,7 +288,7 @@ matrix:
env: CMAKE_TEST=1
script:
- mkdir __build__ && cd __build__
- cmake -DBOOST_ENABLE_CMAKE=1 -DBoost_VERBOSE=1 -DBOOST_INCLUDE_LIBRARIES=variant2 ..
- cmake -DBOOST_ENABLE_CMAKE=1 -DBUILD_TESTING=ON -DBoost_VERBOSE=1 -DBOOST_INCLUDE_LIBRARIES=variant2 ..
- ctest --output-on-failure -R boost_variant2
- os: linux

View File

@ -1,8 +1,11 @@
# Copyright 2018, 2019 Peter Dimov
# Generated by `boostdep --cmake variant2`
# Copyright 2020, 2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# http://www.boost.org/LICENSE_1_0.txt
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.16)
if(NOT DEFINED IDF_TARGET)
cmake_minimum_required(VERSION 3.8...3.20)
project(boost_variant2 VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
@ -13,12 +16,34 @@ target_include_directories(boost_variant2 INTERFACE include)
target_link_libraries(boost_variant2
INTERFACE
Boost::assert
Boost::config
Boost::mp11
)
if(BUILD_TESTING)
target_compile_features(boost_variant2 INTERFACE cxx_std_11)
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()
else()
FILE(GLOB_RECURSE headers include/*.h include/*.hpp)
idf_component_register(
SRCS
${headers}
INCLUDE_DIRS
include
REQUIRES
boost_assert
boost_config
boost_mp11
)
endif()

View File

@ -1,21 +1,18 @@
# variant2
# Boost.Variant2
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 library is part of Boost, starting from release 1.71, 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. It depends on
Boost.Mp11, Boost.Config, and Boost.Assert.
Supported compilers:
* g++ 4.8 or later with `-std=c++11` or above
* clang++ 3.5 or later with `-std=c++11` or above
* clang++ 3.9 or later with `-std=c++11` or above
* Visual Studio 2015, 2017, 2019
Tested on [Travis](https://travis-ci.org/boostorg/variant2/) and
Tested on [Github Actions](https://github.com/boostorg/variant2/actions) and
[Appveyor](https://ci.appveyor.com/project/pdimov/variant2-fkab9).

View File

@ -1,4 +1,4 @@
# Copyright 2016-2020 Peter Dimov
# Copyright 2016-2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
@ -29,6 +29,10 @@ environment:
TOOLSET: msvc-14.2
ADDRMD: 32,64
CXXSTD: 14,17,latest
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: clang-win
ADDRMD: 64
CXXSTD: 14,17,latest
install:
- set BOOST_BRANCH=develop
@ -47,4 +51,4 @@ build: off
test_script:
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
- b2 -j3 libs/variant2/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release
- b2 -j3 libs/variant2/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker

View File

@ -13,6 +13,8 @@ Peter Dimov
:toclevels: 4
:idprefix:
:docinfo: private-footer
:source-highlighter: rouge
:source-language: c++
:leveloffset: +1

View File

@ -1,16 +1,24 @@
////
Copyright 2019-2021 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt
https://www.boost.org/LICENSE_1_0.txt
////
[#changelog]
# Revision History
:idprefix: changelog_
## Changes in 1.79.0
* Added `operator<<` for `monostate`.
## Changes in 1.78.0
* Added `<boost/variant2.hpp>`.
* Added `unsafe_get<I>`.
* Added `visit_by_index`.
* Added `operator<<`.
## Changes in 1.76.0
* Improved generated code for the double buffered case.

View File

@ -169,6 +169,10 @@ 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.)
* `unsafe_get`, an unchecked alternative to `get` and `get_if`, is provided
as an extension.
* `visit_by_index`, a visitation function that takes a single variant and a
number of function objects, one per alternative, is provided as an extension.
* The {cpp}20 additions and changes to `std::variant` have not yet been
implemented.

View File

@ -1,10 +1,7 @@
////
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
https://www.boost.org/LICENSE_1_0.txt
////
[#implementation]
@ -13,13 +10,13 @@ http://www.boost.org/LICENSE_1_0.txt
## Dependencies
This implementation only depends on Boost.Config and Boost.Mp11.
This implementation only depends on Boost.Config, Boost.Assert, 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
* Clang 3.9 or later with `-std=c++11` or above
* Visual Studio 2015, 2017, 2019
Tested on https://travis-ci.org/boostorg/variant2/[Travis] and
Tested on https://github.com/boostorg/variant2/actions[Github Actions] and
https://ci.appveyor.com/project/pdimov/variant2-fkab9[Appveyor].

View File

@ -1,10 +1,7 @@
////
Copyright 2018, 2019 Peter Dimov
Copyright 2018-2021 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt
https://www.boost.org/LICENSE_1_0.txt
////
[#reference]
@ -117,6 +114,21 @@ template<class U, class... T>
constexpr add_pointer_t<const U>
get_if(const variant<T...>* v) noexcept;
// unsafe_get (extension)
template<size_t I, class... T>
constexpr variant_alternative_t<I, variant<T...>>&
unsafe_get(variant<T...>& v);
template<size_t I, class... T>
constexpr variant_alternative_t<I, variant<T...>>&&
unsafe_get(variant<T...>&& v);
template<size_t I, class... T>
constexpr const variant_alternative_t<I, variant<T...>>&
unsafe_get(const variant<T...>& v);
template<size_t I, class... T>
constexpr const variant_alternative_t<I, variant<T...>>&&
unsafe_get(const variant<T...>&& v);
// relational operators
template<class... T>
@ -132,11 +144,21 @@ template<class... T>
template<class... T>
constexpr bool operator>=(const variant<T...>& v, const variant<T...>& w);
// swap
template<class... T>
void swap(variant<T...>& v, variant<T...>& w) noexcept( /*see below*/ );
// visit
template<class R = /*unspecified*/, class F, class... V>
constexpr /*see below*/ visit(F&& f, V&&... v);
// visit_by_index (extension)
template<class R = /*unspecified*/, class V, class... F>
constexpr /*see below*/ visit_by_index(V&& v, F&&.. f);
// monostate
struct monostate {};
@ -148,10 +170,15 @@ constexpr bool operator>(monostate, monostate) noexcept { return false; }
constexpr bool operator<=(monostate, monostate) noexcept { return true; }
constexpr bool operator>=(monostate, monostate) noexcept { return true; }
// swap
// stream insertion (extension)
template<class... T>
void swap(variant<T...>& v, variant<T...>& w) noexcept( /*see below*/ );
template<class Ch, class Tr, class... T>
std::basic_ostream<Ch, Tr>&
operator<<( std::basic_ostream<Ch, Tr>& os, variant<T...> const& v );
template<class Ch, class Tr>
std::basic_ostream<Ch, Tr>&
operator<<( std::basic_ostream<Ch, Tr>& os, monostate const& v );
// bad_variant_access
@ -775,6 +802,34 @@ Requires: :: The type `U` occurs exactly once in `T...`. Otherwise, the
Effects: :: Equivalent to: `return get_if<I>(v);` with `I` being
the zero-based index of `U` in `T...`.
### unsafe_get (extension)
```
template<size_t I, class... T>
constexpr variant_alternative_t<I, variant<T...>>&
unsafe_get(variant<T...>& v);
```
```
template<size_t I, class... T>
constexpr variant_alternative_t<I, variant<T...>>&&
unsafe_get(variant<T...>&& v);
```
```
template<size_t I, class... T>
constexpr const variant_alternative_t<I, variant<T...>>&
unsafe_get(const variant<T...>& v);
```
```
template<size_t I, class... T>
constexpr const variant_alternative_t<I, variant<T...>>&&
unsafe_get(const variant<T...>&& v);
```
[none]
* {blank}
+
Requires: :: `v.index() == I`.
Returns: :: a reference to the object stored in the variant.
### Relational Operators
```
@ -835,6 +890,18 @@ template<class... T>
Returns: ::
`w \<= v`.
### swap
```
template<class... T>
void swap(variant<T...>& v, variant<T...>& w) noexcept( /*see below*/ );
```
[none]
* {blank}
+
Effects: ::
Equivalent to `v.swap(w)`.
### visit
```
@ -851,17 +918,50 @@ Remarks: :: If `R` is given explicitly, as in `visit<int>`, the return
of `F` to the variant alternatives must have the same return type for
this deduction to succeed.
### swap
### visit_by_index (extension)
```
template<class... T>
void swap(variant<T...>& v, variant<T...>& w) noexcept( /*see below*/ );
template<class R = /*unspecified*/, class V, class... F>
constexpr /*see below*/ visit_by_index(V&& v, F&&.. f);
```
[none]
* {blank}
+
Requires: :: `variant_size<V>::value == sizeof...(F)`, or the program is ill-formed.
Returns: :: `std::forward<Fi>(fi)(get<i>(std::forward<V>(v)))`, where
`i` is `v.index()` and `Fi` and `fi` are the `i`-th element of `F...` and `f...`
accordingly.
Remarks: :: If `R` is given explicitly, as in `visit_by_index<int>`, the return
type is `R`. Otherwise, it's deduced from `F...` and `V`. All the applications
of `Fi` to the corresponding variant alternatives must have the same return type
for this deduction to succeed.
### Stream Insertion (extension)
```
template<class Ch, class Tr, class... T>
std::basic_ostream<Ch, Tr>&
operator<<( std::basic_ostream<Ch, Tr>& os, variant<T...> const& v );
```
[none]
* {blank}
+
Requires: ::
`sizeof...(T) != 0`.
Returns: ::
`os << get<I>(v)`, where `I` is `v.index()`.
```
template<class Ch, class Tr>
std::basic_ostream<Ch, Tr>&
operator<<( std::basic_ostream<Ch, Tr>& os, monostate const& v );
```
[none]
* {blank}
+
Effects: ::
Equivalent to `v.swap(w)`.
`os << "monostate"`.
Returns: ::
`os`.
### bad_variant_access
@ -878,3 +978,7 @@ public:
}
};
```
## <boost/variant2.hpp>
This convenience header includes `<boost/variant2/variant.hpp>`.

View File

@ -0,0 +1,10 @@
#ifndef BOOST_VARIANT2_HPP_INCLUDED
#define BOOST_VARIANT2_HPP_INCLUDED
// Copyright 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
#endif // #ifndef BOOST_VARIANT2_HPP_INCLUDED

View File

@ -13,19 +13,19 @@
# pragma warning( disable: 4521 4522 ) // multiple copy operators
#endif
#ifndef BOOST_MP11_HPP_INCLUDED
#include <boost/mp11.hpp>
#endif
#include <boost/assert.hpp>
#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
#include <cstdint>
#include <iosfwd>
//
@ -38,6 +38,8 @@ BOOST_NORETURN void throw_exception( std::exception const & e ); // user defined
#endif
template<class T> struct hash;
namespace variant2
{
@ -364,37 +366,50 @@ template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T
#endif
}
// detail::unsafe_get (for visit)
// unsafe_get
namespace detail
{
#if !defined(BOOST_NO_CXX14_CONSTEXPR)
# define BOOST_VARIANT2_CX14_ASSERT(expr) BOOST_ASSERT(expr);
#else
# define BOOST_VARIANT2_CX14_ASSERT(expr)
#endif
template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T...>>& unsafe_get(variant<T...>& v)
{
static_assert( I < sizeof...(T), "Index out of bounds" );
BOOST_VARIANT2_CX14_ASSERT( v.index() == I )
return v._get_impl( mp11::mp_size_t<I>() );
}
template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T...>>&& unsafe_get(variant<T...>&& v)
{
static_assert( I < sizeof...(T), "Index out of bounds" );
BOOST_VARIANT2_CX14_ASSERT( v.index() == I )
return std::move( v._get_impl( mp11::mp_size_t<I>() ) );
}
template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T...>> const& unsafe_get(variant<T...> const& v)
{
static_assert( I < sizeof...(T), "Index out of bounds" );
BOOST_VARIANT2_CX14_ASSERT( v.index() == I )
return v._get_impl( mp11::mp_size_t<I>() );
}
template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T...>> const&& unsafe_get(variant<T...> const&& v)
{
static_assert( I < sizeof...(T), "Index out of bounds" );
BOOST_VARIANT2_CX14_ASSERT( v.index() == I )
return std::move( v._get_impl( mp11::mp_size_t<I>() ) );
}
} // namespace detail
// get (type)
template<class U, class... T> constexpr U& get(variant<T...>& v)
@ -827,14 +842,14 @@ struct none {};
// trivially destructible, single buffered
template<class... T> struct variant_base_impl<true, true, T...>
{
unsigned ix_;
variant_storage<none, T...> st_;
unsigned ix_;
constexpr variant_base_impl(): ix_( 0 ), st_( mp11::mp_size_t<0>() )
constexpr variant_base_impl(): st_( mp11::mp_size_t<0>() ), ix_( 0 )
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... )
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): st_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... ), ix_( I::value + 1 )
{
}
@ -854,7 +869,7 @@ template<class... T> struct variant_base_impl<true, true, T...>
{
size_t const J = I+1;
assert( ix_ == J );
BOOST_ASSERT( ix_ == J );
return st_.get( mp11::mp_size_t<J>() );
}
@ -862,7 +877,8 @@ template<class... T> struct variant_base_impl<true, true, T...>
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
{
// size_t const J = I+1;
// assert( ix_ == I+1 );
BOOST_VARIANT2_CX14_ASSERT( ix_ == I+1 )
return st_.get( mp11::mp_size_t<I+1>() );
}
@ -897,14 +913,14 @@ template<class... T> struct variant_base_impl<true, true, T...>
// trivially destructible, double buffered
template<class... T> struct variant_base_impl<true, false, T...>
{
unsigned ix_;
variant_storage<none, T...> st_[ 2 ];
unsigned ix_;
constexpr variant_base_impl(): ix_( 0 ), st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } }
constexpr variant_base_impl(): st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } }, ix_( 0 )
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st_{ { mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... }, { mp11::mp_size_t<0>() } }
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): st_{ { mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... }, { mp11::mp_size_t<0>() } }, ix_( ( I::value + 1 ) * 2 )
{
}
@ -922,7 +938,7 @@ template<class... T> struct variant_base_impl<true, false, T...>
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<variant<T...>, I>& _get_impl( mp11::mp_size_t<I> ) noexcept
{
assert( index() == I );
BOOST_ASSERT( index() == I );
size_t const J = I+1;
@ -932,7 +948,8 @@ template<class... T> struct variant_base_impl<true, false, T...>
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
{
// assert( index() == I );
BOOST_VARIANT2_CX14_ASSERT( index() == I )
// size_t const J = I+1;
// constexpr mp_size_t<J> j{};
@ -954,14 +971,14 @@ template<class... T> struct variant_base_impl<true, false, T...>
// not trivially destructible, single buffered
template<class... T> struct variant_base_impl<false, true, T...>
{
unsigned ix_;
variant_storage<none, T...> st_;
unsigned ix_;
constexpr variant_base_impl(): ix_( 0 ), st_( mp11::mp_size_t<0>() )
constexpr variant_base_impl(): st_( mp11::mp_size_t<0>() ), ix_( 0 )
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... )
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): st_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... ), ix_( I::value + 1 )
{
}
@ -1010,7 +1027,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
{
size_t const J = I+1;
assert( ix_ == J );
BOOST_ASSERT( ix_ == J );
return st_.get( mp11::mp_size_t<J>() );
}
@ -1018,7 +1035,8 @@ template<class... T> struct variant_base_impl<false, true, T...>
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
{
// size_t const J = I+1;
// assert( ix_ == J );
BOOST_VARIANT2_CX14_ASSERT( ix_ == I+1 )
return st_.get( mp11::mp_size_t<I+1>() );
}
@ -1043,19 +1061,18 @@ template<class... T> struct variant_base_impl<false, true, T...>
// not trivially destructible, double buffered
template<class... T> struct variant_base_impl<false, false, T...>
{
unsigned ix_;
#if defined(__GNUC__) && __GNUC__ < 11 && !defined(__clang__) && !defined(__INTEL_COMPILER)
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63707 :-(
variant_storage<none, T...> st1_, st2_;
unsigned ix_;
constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() ), st2_( mp11::mp_size_t<0>() )
constexpr variant_base_impl(): st1_( mp11::mp_size_t<0>() ), st2_( mp11::mp_size_t<0>() ), ix_( 0 )
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... ), st2_( mp11::mp_size_t<0>() )
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... ), st2_( mp11::mp_size_t<0>() ), ix_( ( I::value + 1 ) * 2 )
{
}
@ -1072,12 +1089,13 @@ template<class... T> struct variant_base_impl<false, false, T...>
#else
variant_storage<none, T...> st_[ 2 ];
unsigned ix_;
constexpr variant_base_impl(): ix_( 0 ), st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } }
constexpr variant_base_impl(): st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } }, ix_( 0 )
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st_{ { mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... }, { mp11::mp_size_t<0>() } }
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): st_{ { mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... }, { mp11::mp_size_t<0>() } }, ix_( ( I::value + 1 ) * 2 )
{
}
@ -1134,7 +1152,7 @@ template<class... T> struct variant_base_impl<false, false, T...>
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<variant<T...>, I>& _get_impl( mp11::mp_size_t<I> ) noexcept
{
assert( index() == I );
BOOST_ASSERT( index() == I );
size_t const J = I+1;
@ -1144,7 +1162,8 @@ template<class... T> struct variant_base_impl<false, false, T...>
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
{
// assert( index() == I );
BOOST_VARIANT2_CX14_ASSERT( index() == I )
// size_t const J = I+1;
// constexpr mp_size_t<J> j{};
@ -1581,7 +1600,7 @@ public:
template<class U,
class Ud = typename std::decay<U>::type,
class E1 = typename std::enable_if< !std::is_same<Ud, variant>::value && !detail::is_in_place_index<Ud>::value && !detail::is_in_place_type<Ud>::value >::type,
class E1 = typename std::enable_if< !std::is_same<Ud, variant>::value && !std::is_base_of<variant, Ud>::value && !detail::is_in_place_index<Ud>::value && !detail::is_in_place_type<Ud>::value >::type,
class V = detail::resolve_overload_type<U&&, T...>,
class E2 = typename std::enable_if<std::is_constructible<V, U&&>::value>::type
>
@ -2173,7 +2192,7 @@ template<class R = detail::deduced, class F, class V1, class V2, class... V> con
{
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)... ); };
auto f2 = [&]( auto&&... a ){ return std::forward<F>(f)( unsafe_get<I.value>( std::forward<V1>(v1) ), std::forward<decltype(a)>(a)... ); };
return visit<R>( f2, std::forward<V2>(v2), std::forward<V>(v)... );
});
@ -2190,36 +2209,133 @@ void swap( variant<T...> & v, variant<T...> & w )
v.swap( w );
}
// visit_by_index
namespace detail
{
template<class R, class V, class... F> using Vret2 = mp11::mp_eval_if_not< std::is_same<R, deduced>, R, front_if_same, mp11::mp_transform<mp11::mp_invoke_q, mp11::mp_list<Qret<F>...>, apply_cv_ref<V>> >;
template<class R, class V, class... F> struct visit_by_index_L
{
V&& v;
std::tuple<F&&...> tp;
template<class I> constexpr detail::Vret2<R, V, F...> operator()( I ) const
{
return std::get<I::value>( std::move(tp) )( unsafe_get<I::value>( std::forward<V>(v) ) );
}
};
} // namespace detail
template<class R = detail::deduced, class V, class... F> constexpr auto visit_by_index( V&& v, F&&... f ) -> detail::Vret2<R, V, F...>
{
static_assert( variant_size<V>::value == sizeof...(F), "Incorrect number of function objects" );
return mp11::mp_with_index<variant_size<V>::value>( v.index(),
detail::visit_by_index_L<R, V, F...>{ std::forward<V>(v), std::tuple<F&&...>( std::forward<F>(f)... ) } );
}
// output streaming
namespace detail
{
template<class Ch, class Tr, class... T> struct ostream_insert_L
{
std::basic_ostream<Ch, Tr>& os;
variant<T...> const& v;
template<class I> std::basic_ostream<Ch, Tr>& operator()( I ) const
{
return os << unsafe_get<I::value>( v );
}
};
template<class Os, class T, class E = void> struct is_output_streamable: std::false_type
{
};
template<class Os, class T> struct is_output_streamable<Os, T, decltype( std::declval<Os&>() << std::declval<T const&>(), (void)0 )>: std::true_type
{
};
} // namespace detail
template<class Ch, class Tr>
std::basic_ostream<Ch, Tr>& operator<<( std::basic_ostream<Ch, Tr>& os, monostate const& )
{
os << "monostate";
return os;
}
template<class Ch, class Tr, class T1, class... T,
class E = typename std::enable_if< mp11::mp_all< detail::is_output_streamable<std::basic_ostream<Ch, Tr>, T>... >::value >::type >
std::basic_ostream<Ch, Tr>& operator<<( std::basic_ostream<Ch, Tr>& os, variant<T1, T...> const& v )
{
return mp11::mp_with_index<1 + sizeof...(T)>( v.index(),
detail::ostream_insert_L<Ch, Tr, T1, T...>{ os, v } );
}
// hashing support
namespace detail
{
template<class V> struct hash_value_L
inline std::size_t hash_value_impl_( mp11::mp_true, std::size_t index, std::size_t value )
{
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;
hv ^= index;
hv *= prime;
hv ^= value;
hv *= prime;
return static_cast<std::size_t>( hv );
}
inline std::size_t hash_value_impl_( mp11::mp_false, std::size_t index, std::size_t value )
{
std::size_t hv = 0x811C9DC5;
std::size_t const prime = 0x01000193;
hv ^= index;
hv *= prime;
hv ^= value;
hv *= prime;
return hv;
}
inline std::size_t hash_value_impl( std::size_t index, std::size_t value )
{
return hash_value_impl_( mp11::mp_bool< (SIZE_MAX > UINT32_MAX) >(), index, value );
}
template<template<class> class H, 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;
std::size_t index = I::value;
std::size_t value = H<remove_cv_ref_t<decltype(t)>>()( t );
return static_cast<std::size_t>( hv );
return hash_value_impl( index, value );
}
};
template<class... T> std::size_t hash_value_std( variant<T...> const & v )
{
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::hash_value_L< std::hash, variant<T...> >{ v } );
}
} // namespace detail
inline std::size_t hash_value( monostate const & )
@ -2229,7 +2345,7 @@ inline std::size_t hash_value( monostate const & )
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 } );
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::hash_value_L< boost::hash, variant<T...> >{ v } );
}
namespace detail
@ -2250,7 +2366,7 @@ template<class V> struct std_hash_impl<V, true>
{
std::size_t operator()( V const & v ) const
{
return hash_value( v );
return detail::hash_value_std( v );
}
};
@ -2276,6 +2392,8 @@ template<> struct hash< ::boost::variant2::monostate >
} // namespace std
#undef BOOST_VARIANT2_CX14_ASSERT
#if defined(_MSC_VER) && _MSC_VER < 1910
# pragma warning( pop )
#endif

View File

@ -119,3 +119,10 @@ run variant_visit_r.cpp : : :
<toolset>gcc,<target-os>windows:<variant>release
<toolset>gcc,<target-os>cygwin:<variant>release
;
compile variant_derived_construct.cpp ;
run variant_visit_by_index.cpp ;
run variant_ostream_insert.cpp ;
run is_output_streamable.cpp ;

View File

@ -7,6 +7,8 @@ cmake_minimum_required(VERSION 3.5...3.16)
project(cmake_subdir_test LANGUAGES CXX)
add_subdirectory(../.. boostorg/variant2)
add_subdirectory(../../../assert boostorg/assert)
add_subdirectory(../../../config boostorg/config)
add_subdirectory(../../../mp11 boostorg/mp11)

View File

@ -0,0 +1,41 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <ostream>
#include <string>
struct X
{
};
struct Y
{
};
std::ostream& operator<<( std::ostream& os, Y const& /*y*/ )
{
os << "Y()";
return os;
}
int main()
{
BOOST_TEST_TRAIT_TRUE((boost::variant2::detail::is_output_streamable<std::ostream, int>));
BOOST_TEST_TRAIT_TRUE((boost::variant2::detail::is_output_streamable<std::ostream, float>));
BOOST_TEST_TRAIT_TRUE((boost::variant2::detail::is_output_streamable<std::ostream, std::string>));
BOOST_TEST_TRAIT_FALSE((boost::variant2::detail::is_output_streamable<std::ostream, void>));
BOOST_TEST_TRAIT_FALSE((boost::variant2::detail::is_output_streamable<std::ostream, X>));
BOOST_TEST_TRAIT_TRUE((boost::variant2::detail::is_output_streamable<std::ostream, Y>));
BOOST_TEST_TRAIT_TRUE((boost::variant2::detail::is_output_streamable<std::ostream, boost::variant2::monostate>));
BOOST_TEST_TRAIT_TRUE((boost::variant2::detail::is_output_streamable<std::ostream, boost::variant2::variant<int, float, std::string>>));
BOOST_TEST_TRAIT_FALSE((boost::variant2::detail::is_output_streamable<std::ostream, boost::variant2::variant<int, float, X>>));
BOOST_TEST_TRAIT_TRUE((boost::variant2::detail::is_output_streamable<std::ostream, boost::variant2::variant<int, float, Y>>));
BOOST_TEST_TRAIT_TRUE((boost::variant2::detail::is_output_streamable<std::ostream, boost::variant2::variant<boost::variant2::monostate, int, float>>));
return boost::report_errors();
}

View File

@ -1,10 +1,8 @@
// Copyright 2019 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
#include <boost/variant2.hpp>
using namespace boost::variant2;

View File

@ -0,0 +1,33 @@
// Copyright 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
using namespace boost::variant2;
template<class... T> class X: variant<T...>
{
using base = variant<T...>;
using base::base;
};
struct Y
{
Y( Y const& rhs ) = default;
template<class T> Y( T const& t )
{
t.bar();
}
};
int main()
{
using W = X<int, double, Y>;
W a( 1 );
W b( a );
(void)b;
}

View File

@ -12,6 +12,7 @@
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/config/workaround.hpp>
#include <vector>
using namespace boost::variant2;
@ -47,7 +48,17 @@ template<template<class...> class Hash, class T> void test2()
BOOST_TEST_NE( h2, h3 );
}
struct X {};
struct X
{
int m = 0;
};
std::size_t hash_value( X const& x )
{
return boost::hash<int>()( x.m );
}
struct Y {}; // no hash support
int main()
{
@ -57,6 +68,8 @@ int main()
test<boost::hash, monostate, monostate, monostate>();
test<boost::hash, int, int, float>();
test<boost::hash, monostate, X, std::vector<X>>();
test2<std::hash, int>();
test2<std::hash, float>();
@ -65,7 +78,7 @@ int main()
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910) && ( !defined(_LIBCPP_STD_VER) || _LIBCPP_STD_VER > 11 )
BOOST_TEST_TRAIT_FALSE(( detail::is_hash_enabled<X> ));
BOOST_TEST_TRAIT_FALSE(( detail::is_hash_enabled<Y> ));
#endif

View File

@ -105,9 +105,9 @@ int main()
STATIC_ASSERT( v.index() == 4 );
}
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 110000)
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 120000)
// no idea why this fails on g++ 10
// no idea why this fails on g++ 10/11
#else

View File

@ -102,9 +102,9 @@ int main()
STATIC_ASSERT( holds_alternative<X>(v) );
}
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 110000)
#if BOOST_WORKAROUND(BOOST_GCC, >= 100000 && BOOST_GCC < 120000)
// no idea why this fails on g++ 10
// no idea why this fails on g++ 10/11
#else

View File

@ -0,0 +1,43 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
#include <sstream>
#include <string>
using namespace boost::variant2;
template<class T> std::string to_string( T const& t )
{
std::ostringstream os;
os << t;
return os.str();
}
int main()
{
{
BOOST_TEST_EQ( to_string( monostate() ), "monostate" );
}
{
variant<monostate, int, float, std::string> v;
BOOST_TEST_EQ( to_string( v ), to_string( monostate() ) );
v = 1;
BOOST_TEST_EQ( to_string( v ), to_string( 1 ) );
v = 3.14f;
BOOST_TEST_EQ( to_string( v ), to_string( 3.14f ) );
v = "test";
BOOST_TEST_EQ( to_string( v ), to_string( "test" ) );
}
return boost::report_errors();
}

View File

@ -0,0 +1,126 @@
// Copyright 2017, 2021 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://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 <boost/mp11.hpp>
#include <boost/config.hpp>
using namespace boost::variant2;
using boost::mp11::mp_int;
struct X
{
};
struct F1
{
int operator()( X& ) const { return 1; }
int operator()( X const& ) const { return 2; }
int operator()( X&& ) const { return 3; }
int operator()( X const&& ) const { return 4; }
};
struct F2
{
mp_int<1> operator()( X& ) const { return {}; }
mp_int<2> operator()( X const& ) const { return {}; }
mp_int<3> operator()( X&& ) const { return {}; }
mp_int<4> operator()( X const&& ) const { return {}; }
};
int main()
{
{
variant<int, int, float> v;
visit_by_index( v,
[]( int& x ){ BOOST_TEST_EQ( x, 0 ); },
[]( int& ){ BOOST_ERROR( "incorrect alternative" ); },
[]( float& ){ BOOST_ERROR( "incorrect alternative" ); } );
}
{
variant<int const, int, float const> v( in_place_index_t<0>(), 1 );
visit_by_index( v,
[]( int const& x ){ BOOST_TEST_EQ( x, 1 ); },
[]( int& ){ BOOST_ERROR( "incorrect alternative" ); },
[]( float const& ){ BOOST_ERROR( "incorrect alternative" ); } );
}
{
variant<int, int, float> const v( in_place_index_t<1>(), 2 );
visit_by_index( v,
[]( int const& ){ BOOST_ERROR( "incorrect alternative" ); },
[]( int const& x ){ BOOST_TEST_EQ( x, 2 ); },
[]( float const& ){ BOOST_ERROR( "incorrect alternative" ); } );
}
{
variant<int const, int, float const> const v( 3.14f );
visit_by_index( v,
[]( int const& ){ BOOST_ERROR( "incorrect alternative" ); },
[]( int const& ){ BOOST_ERROR( "incorrect alternative" ); },
[]( float const& x ){ BOOST_TEST_EQ( x, 3.14f ); } );
}
{
variant<int, float> const v( 7 );
auto r = visit_by_index( v,
[]( int const& x ) -> double { return x; },
[]( float const& x ) -> double { return x; } );
BOOST_TEST_TRAIT_SAME( decltype(r), double );
BOOST_TEST_EQ( r, 7.0 );
}
{
variant<int, float> const v( 2.0f );
auto r = visit_by_index( v,
[]( int const& x ) { return x + 0.0; },
[]( float const& x ) { return x + 0.0; } );
BOOST_TEST_TRAIT_SAME( decltype(r), double );
BOOST_TEST_EQ( r, 2.0 );
}
{
variant<int, float, double> const v( 3.0 );
auto r = visit_by_index<double>( v,
[]( int const& x ) { return x; },
[]( float const& x ) { return x; },
[]( double const& x ) { return x; } );
BOOST_TEST_TRAIT_SAME( decltype(r), double );
BOOST_TEST_EQ( r, 3.0 );
}
{
variant<X> v;
variant<X> const cv;
F1 f1;
BOOST_TEST_EQ( visit_by_index( v, f1 ), 1 );
BOOST_TEST_EQ( visit_by_index( cv, f1 ), 2 );
BOOST_TEST_EQ( visit_by_index( std::move( v ), f1 ), 3 );
BOOST_TEST_EQ( visit_by_index( std::move( cv ), f1 ), 4 );
F2 f2;
BOOST_TEST_EQ( visit_by_index<int>( v, f2 ), 1 );
BOOST_TEST_EQ( visit_by_index<int>( cv, f2 ), 2 );
BOOST_TEST_EQ( visit_by_index<int>( std::move( v ), f2 ), 3 );
BOOST_TEST_EQ( visit_by_index<int>( std::move( cv ), f2 ), 4 );
}
return boost::report_errors();
}

View File

@ -1,4 +1,3 @@
// Copyright 2017, 2020 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
@ -15,7 +14,7 @@
struct X: boost::variant2::variant<int, float>
{
#if BOOST_WORKAROUND( BOOST_MSVC, < 1930 )
#if BOOST_WORKAROUND( BOOST_MSVC, < 1940 )
template<class T> explicit X( T&& t ): variant( std::forward<T>( t ) ) {};