Compare commits

...

33 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
20 changed files with 718 additions and 112 deletions

View File

@ -19,18 +19,15 @@ jobs:
include: include:
- toolset: gcc-4.8 - toolset: gcc-4.8
cxxstd: "03,11" cxxstd: "03,11"
os: ubuntu-16.04 os: ubuntu-18.04
install: g++-4.8 install: g++-4.8
- toolset: gcc-4.9
cxxstd: "03,11"
os: ubuntu-16.04
install: g++-4.9
- toolset: gcc-5 - toolset: gcc-5
cxxstd: "03,11,14,1z" cxxstd: "03,11,14,1z"
os: ubuntu-16.04 os: ubuntu-18.04
install: g++-5
- toolset: gcc-6 - toolset: gcc-6
cxxstd: "03,11,14,1z" cxxstd: "03,11,14,1z"
os: ubuntu-16.04 os: ubuntu-18.04
install: g++-6 install: g++-6
- toolset: gcc-7 - toolset: gcc-7
cxxstd: "03,11,14,17" cxxstd: "03,11,14,17"
@ -41,44 +38,29 @@ jobs:
install: g++-8 install: g++-8
- toolset: gcc-9 - toolset: gcc-9
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04 os: ubuntu-20.04
- toolset: gcc-10 - toolset: gcc-10
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04 os: ubuntu-20.04
- toolset: clang install: g++-10
compiler: clang++-3.5 - toolset: gcc-11
cxxstd: "03,11,14" cxxstd: "03,11,14,17,2a"
os: ubuntu-16.04 os: ubuntu-20.04
install: clang-3.5 install: g++-11
- toolset: clang
compiler: clang++-3.6
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.6
- toolset: clang
compiler: clang++-3.7
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.7
- toolset: clang
compiler: clang++-3.8
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.8
- toolset: clang - toolset: clang
compiler: clang++-3.9 compiler: clang++-3.9
cxxstd: "03,11,14" cxxstd: "03,11,14"
os: ubuntu-16.04 os: ubuntu-18.04
install: clang-3.9 install: clang-3.9
- toolset: clang - toolset: clang
compiler: clang++-4.0 compiler: clang++-4.0
cxxstd: "03,11,14" cxxstd: "03,11,14"
os: ubuntu-16.04 os: ubuntu-18.04
install: clang-4.0 install: clang-4.0
- toolset: clang - toolset: clang
compiler: clang++-5.0 compiler: clang++-5.0
cxxstd: "03,11,14,1z" cxxstd: "03,11,14,1z"
os: ubuntu-16.04 os: ubuntu-18.04
install: clang-5.0 install: clang-5.0
- toolset: clang - toolset: clang
compiler: clang++-6.0 compiler: clang++-6.0
@ -92,21 +74,29 @@ jobs:
install: clang-7 install: clang-7
- toolset: clang - toolset: clang
compiler: clang++-8 compiler: clang++-8
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17"
os: ubuntu-20.04 os: ubuntu-20.04
install: clang-8 install: clang-8
- toolset: clang - toolset: clang
compiler: clang++-9 compiler: clang++-9
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04 os: ubuntu-20.04
install: clang-9
- toolset: clang - toolset: clang
compiler: clang++-10 compiler: clang++-10
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04 os: ubuntu-20.04
install: clang-10
- toolset: clang - toolset: clang
compiler: clang++-11 compiler: clang++-11
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04 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 - toolset: clang
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
os: macos-10.15 os: macos-10.15
@ -157,6 +147,10 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- toolset: msvc-14.0
cxxstd: "14"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.1 - toolset: msvc-14.1
cxxstd: "14,17,latest" cxxstd: "14,17,latest"
addrmd: 32,64 addrmd: 32,64
@ -165,6 +159,10 @@ jobs:
cxxstd: "14,17,latest" cxxstd: "14,17,latest"
addrmd: 32,64 addrmd: 32,64
os: windows-2019 os: windows-2019
- toolset: msvc-14.3
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2022
- toolset: gcc - toolset: gcc
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
addrmd: 64 addrmd: 64
@ -202,3 +200,159 @@ jobs:
run: | run: |
cd ../boost-root cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release 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,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. # 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) 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 target_link_libraries(boost_variant2
INTERFACE INTERFACE
Boost::assert
Boost::config Boost::config
Boost::mp11 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) add_subdirectory(test)
endif() 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 This repository contains a never-valueless, strong guarantee, C++11/14/17
implementation of [std::variant](http://en.cppreference.com/w/cpp/utility/variant). implementation of [std::variant](http://en.cppreference.com/w/cpp/utility/variant).
See [the documentation](https://www.boost.org/libs/variant2) See [the documentation](https://www.boost.org/libs/variant2)
for more information. for more information.
The code requires [Boost.Mp11](https://github.com/boostorg/mp11) and The library is part of Boost, starting from release 1.71. It depends on
Boost.Config. Boost.Mp11, Boost.Config, and Boost.Assert.
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: Supported compilers:
* g++ 4.8 or later with `-std=c++11` or above * 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 * 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). [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. # 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) # (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 TOOLSET: msvc-14.2
ADDRMD: 32,64 ADDRMD: 32,64
CXXSTD: 14,17,latest CXXSTD: 14,17,latest
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: clang-win
ADDRMD: 64
CXXSTD: 14,17,latest
install: install:
- set BOOST_BRANCH=develop - set BOOST_BRANCH=develop
@ -47,4 +51,4 @@ build: off
test_script: test_script:
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD% - 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 :toclevels: 4
:idprefix: :idprefix:
:docinfo: private-footer :docinfo: private-footer
:source-highlighter: rouge
:source-language: c++
:leveloffset: +1 :leveloffset: +1

View File

@ -1,16 +1,24 @@
//// ////
Copyright 2019-2021 Peter Dimov Copyright 2019-2021 Peter Dimov
Distributed under the Boost Software License, Version 1.0. Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt
//// ////
[#changelog] [#changelog]
# Revision History # Revision History
:idprefix: changelog_ :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 ## Changes in 1.76.0
* Improved generated code for the double buffered case. * 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...>`. `variant<int, float>` is provided as the member function `subset<U...>`.
(This operation can throw if the current state of the variant cannot be (This operation can throw if the current state of the variant cannot be
represented.) 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 * The {cpp}20 additions and changes to `std::variant` have not yet been
implemented. implemented.

View File

@ -1,10 +1,7 @@
//// ////
Copyright 2019 Peter Dimov Copyright 2019 Peter Dimov
Distributed under the Boost Software License, Version 1.0. Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt
//// ////
[#implementation] [#implementation]
@ -13,13 +10,13 @@ http://www.boost.org/LICENSE_1_0.txt
## Dependencies ## 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 ## Supported Compilers
* GCC 4.8 or later with `-std=c++11` or above * 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 * 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]. 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. Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt
//// ////
[#reference] [#reference]
@ -117,6 +114,21 @@ template<class U, class... T>
constexpr add_pointer_t<const U> constexpr add_pointer_t<const U>
get_if(const variant<T...>* v) noexcept; 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 // relational operators
template<class... T> template<class... T>
@ -132,11 +144,21 @@ template<class... T>
template<class... T> template<class... T>
constexpr bool operator>=(const variant<T...>& v, const variant<T...>& w); 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 // visit
template<class R = /*unspecified*/, class F, class... V> template<class R = /*unspecified*/, class F, class... V>
constexpr /*see below*/ visit(F&& f, V&&... 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 // monostate
struct 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; }
constexpr bool operator>=(monostate, monostate) noexcept { return true; } constexpr bool operator>=(monostate, monostate) noexcept { return true; }
// swap // stream insertion (extension)
template<class... T> template<class Ch, class Tr, class... T>
void swap(variant<T...>& v, variant<T...>& w) noexcept( /*see below*/ ); 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 // 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 Effects: :: Equivalent to: `return get_if<I>(v);` with `I` being
the zero-based index of `U` in `T...`. 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 ### Relational Operators
``` ```
@ -835,6 +890,18 @@ template<class... T>
Returns: :: Returns: ::
`w \<= v`. `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 ### 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 of `F` to the variant alternatives must have the same return type for
this deduction to succeed. this deduction to succeed.
### swap ### visit_by_index (extension)
``` ```
template<class... T> template<class R = /*unspecified*/, class V, class... F>
void swap(variant<T...>& v, variant<T...>& w) noexcept( /*see below*/ ); 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] [none]
* {blank} * {blank}
+ +
Effects: :: Effects: ::
Equivalent to `v.swap(w)`. `os << "monostate"`.
Returns: ::
`os`.
### bad_variant_access ### 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,20 +13,19 @@
# pragma warning( disable: 4521 4522 ) // multiple copy operators # pragma warning( disable: 4521 4522 ) // multiple copy operators
#endif #endif
#ifndef BOOST_MP11_HPP_INCLUDED
#include <boost/mp11.hpp> #include <boost/mp11.hpp>
#endif #include <boost/assert.hpp>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/detail/workaround.hpp> #include <boost/detail/workaround.hpp>
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <cstddef> #include <cstddef>
#include <type_traits> #include <type_traits>
#include <exception> #include <exception>
#include <cassert>
#include <initializer_list> #include <initializer_list>
#include <utility> #include <utility>
#include <functional> // std::hash #include <functional> // std::hash
#include <cstdint> #include <cstdint>
#include <iosfwd>
// //
@ -367,37 +366,50 @@ template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T
#endif #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) 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" ); 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>() ); 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) 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" ); 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>() ) ); 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) 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" ); 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>() ); 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) 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" ); 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>() ) ); return std::move( v._get_impl( mp11::mp_size_t<I>() ) );
} }
} // namespace detail
// get (type) // get (type)
template<class U, class... T> constexpr U& get(variant<T...>& v) template<class U, class... T> constexpr U& get(variant<T...>& v)
@ -830,14 +842,14 @@ struct none {};
// trivially destructible, single buffered // trivially destructible, single buffered
template<class... T> struct variant_base_impl<true, true, T...> template<class... T> struct variant_base_impl<true, true, T...>
{ {
unsigned ix_;
variant_storage<none, T...> st_; 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 )
{ {
} }
@ -857,7 +869,7 @@ template<class... T> struct variant_base_impl<true, true, T...>
{ {
size_t const J = I+1; size_t const J = I+1;
assert( ix_ == J ); BOOST_ASSERT( ix_ == J );
return st_.get( mp11::mp_size_t<J>() ); return st_.get( mp11::mp_size_t<J>() );
} }
@ -865,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 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; // 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>() ); return st_.get( mp11::mp_size_t<I+1>() );
} }
@ -900,14 +913,14 @@ template<class... T> struct variant_base_impl<true, true, T...>
// trivially destructible, double buffered // trivially destructible, double buffered
template<class... T> struct variant_base_impl<true, false, T...> template<class... T> struct variant_base_impl<true, false, T...>
{ {
unsigned ix_;
variant_storage<none, T...> st_[ 2 ]; 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 )
{ {
} }
@ -925,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 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; size_t const J = I+1;
@ -935,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 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; // size_t const J = I+1;
// constexpr mp_size_t<J> j{}; // constexpr mp_size_t<J> j{};
@ -957,14 +971,14 @@ template<class... T> struct variant_base_impl<true, false, T...>
// not trivially destructible, single buffered // not trivially destructible, single buffered
template<class... T> struct variant_base_impl<false, true, T...> template<class... T> struct variant_base_impl<false, true, T...>
{ {
unsigned ix_;
variant_storage<none, T...> st_; 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 )
{ {
} }
@ -1013,7 +1027,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
{ {
size_t const J = I+1; size_t const J = I+1;
assert( ix_ == J ); BOOST_ASSERT( ix_ == J );
return st_.get( mp11::mp_size_t<J>() ); return st_.get( mp11::mp_size_t<J>() );
} }
@ -1021,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 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; // 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>() ); return st_.get( mp11::mp_size_t<I+1>() );
} }
@ -1046,19 +1061,18 @@ template<class... T> struct variant_base_impl<false, true, T...>
// not trivially destructible, double buffered // not trivially destructible, double buffered
template<class... T> struct variant_base_impl<false, false, T...> template<class... T> struct variant_base_impl<false, false, T...>
{ {
unsigned ix_;
#if defined(__GNUC__) && __GNUC__ < 11 && !defined(__clang__) && !defined(__INTEL_COMPILER) #if defined(__GNUC__) && __GNUC__ < 11 && !defined(__clang__) && !defined(__INTEL_COMPILER)
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63707 :-( // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63707 :-(
variant_storage<none, T...> st1_, st2_; 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 )
{ {
} }
@ -1075,12 +1089,13 @@ template<class... T> struct variant_base_impl<false, false, T...>
#else #else
variant_storage<none, T...> st_[ 2 ]; 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 )
{ {
} }
@ -1137,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 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; size_t const J = I+1;
@ -1147,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 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; // size_t const J = I+1;
// constexpr mp_size_t<J> j{}; // constexpr mp_size_t<J> j{};
@ -2176,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 ){ 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)... ); return visit<R>( f2, std::forward<V2>(v2), std::forward<V>(v)... );
}); });
@ -2193,6 +2209,75 @@ void swap( variant<T...> & v, variant<T...> & w )
v.swap( 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 // hashing support
namespace detail namespace detail
@ -2307,6 +2392,8 @@ template<> struct hash< ::boost::variant2::monostate >
} // namespace std } // namespace std
#undef BOOST_VARIANT2_CX14_ASSERT
#if defined(_MSC_VER) && _MSC_VER < 1910 #if defined(_MSC_VER) && _MSC_VER < 1910
# pragma warning( pop ) # pragma warning( pop )
#endif #endif

View File

@ -121,3 +121,8 @@ run variant_visit_r.cpp : : :
; ;
compile variant_derived_construct.cpp ; 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) project(cmake_subdir_test LANGUAGES CXX)
add_subdirectory(../.. boostorg/variant2) add_subdirectory(../.. boostorg/variant2)
add_subdirectory(../../../assert boostorg/assert)
add_subdirectory(../../../config boostorg/config) add_subdirectory(../../../config boostorg/config)
add_subdirectory(../../../mp11 boostorg/mp11) 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. // Copyright 2019 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0. // 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; using namespace boost::variant2;

View File

@ -105,9 +105,9 @@ int main()
STATIC_ASSERT( v.index() == 4 ); 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 #else

View File

@ -102,9 +102,9 @@ int main()
STATIC_ASSERT( holds_alternative<X>(v) ); 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 #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. // Copyright 2017, 2020 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0. // Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt // https://www.boost.org/LICENSE_1_0.txt
@ -15,7 +14,7 @@
struct X: boost::variant2::variant<int, float> 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 ) ) {}; template<class T> explicit X( T&& t ): variant( std::forward<T>( t ) ) {};