Compare commits

...

30 Commits

Author SHA1 Message Date
Peter Dimov
b137164c0d Update documentation 2026-01-22 02:39:43 +02:00
Peter Dimov
6e8f4e955d Relax get<T> constraint to permit duplicate alternatives. Refs #33. 2026-01-21 21:21:46 +02:00
Peter Dimov
3b731db14d Relax holds_alternative constraint to permit duplicate alternatives. Refs #33. 2026-01-21 16:28:21 +02:00
Peter Dimov
25a8596890 Move cxx14_constexpr conditions from test/Jamfile into test sources 2026-01-21 14:58:47 +02:00
Peter Dimov
8237d94f93 Move msvc-14.0 conditions from test/Jamfile into test sources 2026-01-21 14:42:31 +02:00
Peter Dimov
155ed414ab Disable variant_issue_55.cpp on clang-cl 32 bit 2026-01-02 12:29:11 +02:00
Peter Dimov
e6b336ec68 Call boost::core::lwt_init() in variant_issue_55.cpp, because it doesn't invoke any BOOST_TEST macros and clang-win 32 bit hangs w/ assertion 2026-01-02 02:51:46 +02:00
Peter Dimov
799a69eccc Disable -Wmaybe-uninitialized false positive. Refs #55. 2026-01-02 02:21:29 +02:00
Peter Dimov
74f6f0cd96 Fix issue link; fix __cplusplus check 2026-01-01 22:28:25 +02:00
Peter Dimov
fc786d39b3 Rename variant_gcc_false_positive.cpp 2026-01-01 22:21:34 +02:00
Vinnie Falco
382cf33824 Add test for GCC 12+ -Wmaybe-uninitialized false positive
Add variant_gcc_false_positive.cpp to reproduce GCC 12+ spurious
-Wmaybe-uninitialized warnings when copying/moving variant containing
non-trivially-copyable types like std::exception_ptr and std::string.

Tests use boost::system::result which internally uses variant2, and
include coroutine-based tests when C++20 coroutine support is available.

The test uses -O3 optimization to trigger the aggressive inlining that
exposes the false positive where GCC's dataflow analysis cannot prove
the discriminator ensures only initialized alternatives are accessed.

See https://github.com/boostorg/variant2/issues/33
2026-01-01 22:16:48 +02:00
Peter Dimov
4632862a4b msvc-14.5 still needs two more workarounds 2026-01-01 20:04:58 +02:00
Peter Dimov
48ed0a243f Update .drone.jsonnet 2026-01-01 18:45:22 +02:00
Peter Dimov
936a1a95b5 msvc-14.5 still needs the workarounds. sad! 2026-01-01 18:15:20 +02:00
Peter Dimov
fcdaadb0f5 Update .drone.jsonnet 2026-01-01 18:05:28 +02:00
Peter Dimov
540354878c Disable Boost.JSON tests on gcc-4.9 2026-01-01 17:28:41 +02:00
Peter Dimov
2a5aa1c7ad Update ci.yml 2026-01-01 15:52:54 +02:00
Peter Dimov
f267609ad6 Update revision history 2025-10-22 21:03:21 +03:00
Peter Dimov
edf1c7925b Correct CMake version check; VERSION_GREATER 3.18 is true for 3.18.1 2025-10-19 21:07:20 +03:00
Peter Dimov
b9d0499a8f BOOST_TEST_THROWS requires a semicolon after https://github.com/boostorg/core/pull/205 2025-10-18 20:23:49 +03:00
Peter Dimov
a63b03286e Add test/variant_value_construct_cx_2, 3, 4. Refs #53. 2025-10-18 08:24:39 +03:00
Peter Dimov
5661f2ba15 Disable variant_default_construct_cx_4, _5 on Clang < 18 as well 2025-10-18 03:12:52 +03:00
Peter Dimov
9d913eb1a0 Disable variant_default_construct_cx_3 on Clang < 18; earlier versions complain that the type isn't literal. 2025-10-18 03:01:19 +03:00
Peter Dimov
43377dcada Add test/variant_default_construct_cx_5. Refs #53. 2025-10-18 02:49:29 +03:00
Peter Dimov
2af2d02fce Add test/variant_default_construct_cx_4. Refs #53. 2025-10-18 02:41:28 +03:00
Peter Dimov
b2109dee2a Add test/variant_default_construct_cx_3. Refs #53. 2025-10-18 02:37:21 +03:00
Peter Dimov
df001efb54 Add test/variant_default_construct_cx_2. Refs #53. 2025-10-18 02:29:52 +03:00
Peter Dimov
e708866c65 Add more constexpr. Refs #53. 2025-10-17 22:24:26 +03:00
Peter Dimov
28d23c14f6 Update ci.yml 2025-10-17 21:21:02 +03:00
Peter Dimov
8caa1a3484 Update revision history 2025-01-15 19:44:18 +02:00
38 changed files with 1227 additions and 407 deletions

View File

@@ -34,7 +34,6 @@ local linux_pipeline(name, image, environment, packages = "", sources = [], arch
'set -e',
'uname -a',
'echo $DRONE_STAGE_MACHINE',
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
] +
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
@@ -213,6 +212,13 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
"g++-14-multilib",
),
linux_pipeline(
"Linux 25.04 GCC 15 32/64",
"cppalliance/droneubuntu2504:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-15', CXXSTD: '11,14,17,20,23,2c', ADDRMD: '32,64' },
"g++-15-multilib",
),
linux_pipeline(
"Linux 16.04 Clang 3.5",
"cppalliance/droneubuntu1604:1",
@@ -340,40 +346,47 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
),
linux_pipeline(
"Linux 24.04 Clang 17 UBSAN",
"Linux 24.04 Clang 17",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + ubsan,
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' },
"clang-17",
),
linux_pipeline(
"Linux 24.04 Clang 17 ASAN",
"Linux 24.04 Clang 18",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + asan,
"clang-17",
),
linux_pipeline(
"Linux 24.04 Clang 18 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' } + ubsan,
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' },
"clang-18",
),
linux_pipeline(
"Linux 24.04 Clang 18 ASAN",
"Linux 24.04 Clang 19",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' } + asan,
"clang-18",
),
linux_pipeline(
"Linux 24.10 Clang 19",
"cppalliance/droneubuntu2410:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-19', CXXSTD: '11,14,17,20,2b' } + asan,
{ TOOLSET: 'clang', COMPILER: 'clang++-19', CXXSTD: '11,14,17,20,2b' },
"clang-19",
),
linux_pipeline(
"Linux 24.04 Clang 20 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-20', CXXSTD: '11,14,17,20,23,2c' } + ubsan,
"clang-20",
),
linux_pipeline(
"Linux 24.04 Clang 20 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-20', CXXSTD: '11,14,17,20,23,2c' } + asan,
"clang-20",
),
linux_pipeline(
"Linux 25.10 Clang 21",
"cppalliance/droneubuntu2510:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-21', CXXSTD: '11,14,17,20,23,2c' },
"clang-21",
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,1z' } + ubsan,
@@ -437,4 +450,16 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
"cppalliance/dronevs2022:1",
{ TOOLSET: 'msvc-14.3', CXXSTD: '14,17', CXXFLAGS: '/permissive-' },
),
windows_pipeline(
"Windows VS2026 msvc-14.5",
"cppalliance/dronevs2026:1",
{ TOOLSET: 'msvc-14.5', CXXSTD: '14,17,20,latest' },
),
windows_pipeline(
"Windows VS2026 msvc-14.5 permissive-",
"cppalliance/dronevs2026:1",
{ TOOLSET: 'msvc-14.5', CXXSTD: '14,17', CXXFLAGS: '/permissive-' },
),
]

View File

@@ -43,22 +43,27 @@ jobs:
os: ubuntu-latest
- toolset: gcc-8
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: g++-8
- toolset: gcc-9
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
- toolset: gcc-10
cxxstd: "11,14,17,2a"
os: ubuntu-22.04
container: ubuntu:22.04
os: ubuntu-latest
install: g++-10
- toolset: gcc-11
cxxstd: "11,14,17,2a"
os: ubuntu-22.04
container: ubuntu:22.04
os: ubuntu-latest
install: g++-11
- toolset: gcc-12
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
container: ubuntu:22.04
os: ubuntu-latest
install: g++-12
- toolset: gcc-13
cxxstd: "11,14,17,20,2b"
@@ -70,6 +75,11 @@ jobs:
container: ubuntu:24.04
os: ubuntu-latest
install: g++-14
- toolset: gcc-15
cxxstd: "11,14,17,20,23,2c"
container: ubuntu:25.04
os: ubuntu-latest
install: g++-15
- toolset: clang
compiler: clang++-3.9
cxxstd: "11,14"
@@ -91,37 +101,44 @@ jobs:
- toolset: clang
compiler: clang++-6.0
cxxstd: "11,14,17"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-6.0
- toolset: clang
compiler: clang++-7
cxxstd: "11,14,17"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "11,14,17"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-8
- toolset: clang
compiler: clang++-9
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-9
- toolset: clang
compiler: clang++-10
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-10
- toolset: clang
compiler: clang++-11
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-11
- toolset: clang
compiler: clang++-12
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-12
- toolset: clang
compiler: clang++-13
@@ -162,18 +179,30 @@ jobs:
- toolset: clang
compiler: clang++-19
cxxstd: "11,14,17,20,2b"
container: ubuntu:24.10
container: ubuntu:24.04
os: ubuntu-latest
install: clang-19
- toolset: clang
cxxstd: "11,14,17,20,2b"
os: macos-13
compiler: clang++-20
cxxstd: "11,14,17,20,23,2c"
container: ubuntu:24.04
os: ubuntu-latest
install: clang-20
- toolset: clang
compiler: clang++-21
cxxstd: "11,14,17,20,23,2c"
container: ubuntu:25.10
os: ubuntu-latest
install: clang-21
- toolset: clang
cxxstd: "11,14,17,20,2b"
os: macos-14
- toolset: clang
cxxstd: "11,14,17,20,2b"
cxxstd: "11,14,17,20,23,2c"
os: macos-15
- toolset: clang
cxxstd: "11,14,17,20,23,2c"
os: macos-26
runs-on: ${{matrix.os}}
@@ -246,14 +275,6 @@ jobs:
fail-fast: false
matrix:
include:
- toolset: msvc-14.0
cxxstd: "14,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.2
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.3
cxxstd: "14,17,20,latest"
addrmd: 32,64
@@ -265,7 +286,7 @@ jobs:
- toolset: gcc
cxxstd: "11,14,17,2a"
addrmd: 64
os: windows-2019
os: windows-2022
runs-on: ${{matrix.os}}
@@ -305,12 +326,11 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: ubuntu-24.04
- os: macos-13
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
@@ -354,12 +374,11 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: ubuntu-24.04
- os: macos-13
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
@@ -413,12 +432,11 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: ubuntu-24.04
- os: macos-13
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
@@ -470,8 +488,7 @@ jobs:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
- os: windows-latest
runs-on: ${{matrix.os}}
@@ -519,8 +536,7 @@ jobs:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
- os: windows-latest
runs-on: ${{matrix.os}}
@@ -586,8 +602,7 @@ jobs:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
- os: windows-latest
runs-on: ${{matrix.os}}

View File

@@ -19,7 +19,7 @@ target_link_libraries(boost_variant2
Boost::mp11
)
if(CMAKE_VERSION VERSION_GREATER 3.18 AND CMAKE_GENERATOR MATCHES "Visual Studio")
if(NOT CMAKE_VERSION VERSION_LESS 3.19 AND CMAKE_GENERATOR MATCHES "Visual Studio")
file(GLOB_RECURSE boost_variant2_IDEFILES CONFIGURE_DEPENDS include/*.hpp)
source_group(TREE ${PROJECT_SOURCE_DIR}/include FILES ${boost_variant2_IDEFILES} PREFIX "Header Files")

View File

@@ -1,5 +1,5 @@
////
Copyright 2019-2022 Peter Dimov
Copyright 2019-2025 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
@@ -8,6 +8,19 @@ https://www.boost.org/LICENSE_1_0.txt
# Revision History
:idprefix: changelog_
## Changes in 1.91.0
* `holds_alternative<T>` and `get<T>` have been relaxed to no longer require `T` to occur exactly once in the list of alternatives. It now must occur at least once.
## Changes in 1.90.0
* More functions have been marked as `constexpr`, including `~variant`.
This didn't matter before {cpp}20, but does now.
## Changes in 1.88.0
* Use the smallest appropriate unsigned type for the index.
## Changes in 1.83.0
* Added `uses_double_storage()`.

View File

@@ -719,10 +719,8 @@ template<class U, class... T>
[none]
* {blank}
+
Requires: :: The type `U` occurs exactly once in `T...`. Otherwise, the
program is ill-formed.
Returns: :: `true` if `index()` is equal to the zero-based index of `U`
in `T...`.
Requires: :: The type `U` must be present in `T...`. Otherwise, the program is ill-formed.
Returns: :: `true` if `v` holds a value of type `U`, otherwise `false`.
### get
@@ -773,10 +771,8 @@ template<class U, class... T>
[none]
* {blank}
+
Requires: :: The type `U` occurs exactly once in `T...`. Otherwise, the
program is ill-formed.
Effects: :: If `v` holds a value of type `U`, returns a reference to that value.
Otherwise, throws `bad_variant_access`.
Requires: :: The type `U` must be present in `T...`. Otherwise, the program is ill-formed.
Effects: :: If `v` holds a value of type `U`, returns a reference to that value. Otherwise, throws `bad_variant_access`.
### get_if
@@ -793,10 +789,8 @@ template<size_t I, class... T>
[none]
* {blank}
+
Effects: :: A pointer to the value stored in the variant, if
`v != nullptr && v\->index() == I`. Otherwise, `nullptr`.
Remarks: :: These functions do not participate in overload resolution
unless `I` < `sizeof...(T)`.
Returns: :: A pointer to the value stored in `*v`, if `v != nullptr && v\->index() == I`. Otherwise, `nullptr`.
Remarks: :: These functions do not participate in overload resolution unless `I` < `sizeof...(T)`.
```
template<class U, class... T>
@@ -811,10 +805,8 @@ template<class U, class... T>
[none]
* {blank}
+
Requires: :: The type `U` occurs exactly once in `T...`. Otherwise, the
program is ill-formed.
Effects: :: Equivalent to: `return get_if<I>(v);` with `I` being
the zero-based index of `U` in `T...`.
Requires: :: The type `U` must be present in `T...`. Otherwise, the program is ill-formed.
Returns: :: If `v != nullptr` and `*v` holds a value of type `U`, a pointer to that value. Otherwise, `nullptr`.
### unsafe_get (extension)

View File

@@ -1,12 +1,9 @@
#ifndef BOOST_VARIANT2_VARIANT_HPP_INCLUDED
#define BOOST_VARIANT2_VARIANT_HPP_INCLUDED
// Copyright 2017-2019 Peter Dimov.
//
// Copyright 2017-2026 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
#if defined(_MSC_VER) && _MSC_VER < 1910
# pragma warning( push )
@@ -30,6 +27,15 @@
//
// constexpr destructors
#if defined(__cpp_constexpr_dynamic_alloc) && __cpp_constexpr_dynamic_alloc >= 201907L
# define BOOST_VARIANT2_CXX20_CONSTEXPR constexpr
#else
# define BOOST_VARIANT2_CXX20_CONSTEXPR
#endif
//
namespace boost
{
@@ -84,7 +90,7 @@ struct monostate
{
};
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1950)
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1960)
constexpr bool operator<(monostate, monostate) noexcept { return false; }
constexpr bool operator>(monostate, monostate) noexcept { return false; }
@@ -315,12 +321,41 @@ constexpr std::size_t variant_npos = ~static_cast<std::size_t>( 0 );
// holds_alternative
#if !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR)
template<class U, class... T> constexpr bool holds_alternative( variant<T...> const& v ) noexcept
{
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
return v.index() == mp11::mp_find<variant<T...>, U>::value;
static_assert( mp11::mp_contains<variant<T...>, U>::value, "The type must be present in the list of variant alternatives" );
using A = bool[];
return A{ std::is_same<U, T>::value... }[ v.index() ];
}
#else
namespace detail
{
template<class U, class V> struct holds_alternative_L
{
template<class I> constexpr bool operator()( I ) const noexcept
{
return std::is_same< U, mp11::mp_at<V, I> >::value;
}
};
} // namespace detail
template<class U, class... T> constexpr bool holds_alternative( variant<T...> const& v ) noexcept
{
using V = variant<T...>;
static_assert( mp11::mp_contains<V, U>::value, "The type must be present in the list of variant alternatives" );
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::holds_alternative_L<U, V>() );
}
#endif
// get (index)
template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T...>>& get(variant<T...>& v)
@@ -413,61 +448,106 @@ template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T
// get (type)
namespace detail
{
template<class U, class V> struct get_if_impl_L1
{
V& v_;
template<class I> constexpr U* fn( I, mp11::mp_true ) const noexcept
{
return &v_._get_impl( I() );
}
template<class I> constexpr U* fn( I, mp11::mp_false ) const noexcept
{
return nullptr;
}
template<class I> constexpr U* operator()( I ) const noexcept
{
return this->fn( I(), std::is_same<U, mp11::mp_at<V, I>>() );
}
};
template<class U, class... T> constexpr U* get_if_impl( variant<T...>& v ) noexcept
{
return mp11::mp_with_index<sizeof...(T)>( v.index(), get_if_impl_L1< U, variant<T...> >{ v } );
}
template<class U, class V> struct get_if_impl_L2
{
V const& v_;
template<class I> constexpr U const* fn( I, mp11::mp_true ) const noexcept
{
return &v_._get_impl( I() );
}
template<class I> constexpr U const* fn( I, mp11::mp_false ) const noexcept
{
return nullptr;
}
template<class I> constexpr U const* operator()( I ) const noexcept
{
return this->fn( I(), std::is_same<U, mp11::mp_at<V, I>>() );
}
};
template<class U, class... T> constexpr U const* get_if_impl( variant<T...> const& v ) noexcept
{
return mp11::mp_with_index<sizeof...(T)>( v.index(), get_if_impl_L2< U, variant<T...> >{ v } );
}
} // namespace detail
template<class U, class... T> constexpr U& get(variant<T...>& v)
{
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
using I = mp11::mp_find<variant<T...>, U>;
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), v._get_impl( I() );
static_assert( mp11::mp_contains<variant<T...>, U>::value, "The type must be present in the list of variant alternatives" );
return ( !holds_alternative<U>( v )? detail::throw_bad_variant_access(): (void)0 ), *detail::get_if_impl<U>( v );
}
template<class U, class... T> constexpr U&& get(variant<T...>&& v)
{
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
using I = mp11::mp_find<variant<T...>, U>;
static_assert( mp11::mp_contains<variant<T...>, U>::value, "The type must be present in the list of variant alternatives" );
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), std::move( v._get_impl( I() ) );
return ( !holds_alternative<U>( v )? detail::throw_bad_variant_access(): (void)0 ), std::move( *detail::get_if_impl<U>( v ) );
#else
if( v.index() != I::value ) detail::throw_bad_variant_access();
return std::move( v._get_impl( I() ) );
if( !holds_alternative<U>( v ) ) detail::throw_bad_variant_access();
return std::move( *detail::get_if_impl<U>( v ) );
#endif
}
template<class U, class... T> constexpr U const& get(variant<T...> const& v)
{
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
using I = mp11::mp_find<variant<T...>, U>;
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), v._get_impl( I() );
static_assert( mp11::mp_contains<variant<T...>, U>::value, "The type must be present in the list of variant alternatives" );
return ( !holds_alternative<U>( v )? detail::throw_bad_variant_access(): (void)0 ), *detail::get_if_impl<U>( v );
}
template<class U, class... T> constexpr U const&& get(variant<T...> const&& v)
{
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
using I = mp11::mp_find<variant<T...>, U>;
static_assert( mp11::mp_contains<variant<T...>, U>::value, "The type must be present in the list of variant alternatives" );
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), std::move( v._get_impl( I() ) );
return ( !holds_alternative<U>( v )? detail::throw_bad_variant_access(): (void)0 ), std::move( *detail::get_if_impl<U>( v ) );
#else
if( v.index() != I::value ) detail::throw_bad_variant_access();
return std::move( v._get_impl( I() ) );
if( !holds_alternative<U>( v ) ) detail::throw_bad_variant_access();
return std::move( *detail::get_if_impl<U>( v ) );
#endif
}
// get_if
// get_if (index)
template<std::size_t I, class... T> constexpr typename std::add_pointer<variant_alternative_t<I, variant<T...>>>::type get_if(variant<T...>* v) noexcept
{
@@ -481,22 +561,18 @@ template<std::size_t I, class... T> constexpr typename std::add_pointer<const va
return v && v->index() == I? &v->_get_impl( mp11::mp_size_t<I>() ): 0;
}
// get_if (type)
template<class U, class... T> constexpr typename std::add_pointer<U>::type get_if(variant<T...>* v) noexcept
{
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
using I = mp11::mp_find<variant<T...>, U>;
return v && v->index() == I::value? &v->_get_impl( I() ): 0;
static_assert( mp11::mp_contains<variant<T...>, U>::value, "The type must be present in the list of variant alternatives" );
return v && holds_alternative<U>( *v )? detail::get_if_impl<U>( *v ): 0;
}
template<class U, class... T> constexpr typename std::add_pointer<U const>::type get_if(variant<T...> const * v) noexcept
template<class U, class... T> constexpr typename std::add_pointer<U const>::type get_if(variant<T...> const* v) noexcept
{
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
using I = mp11::mp_find<variant<T...>, U>;
return v && v->index() == I::value? &v->_get_impl( I() ): 0;
static_assert( mp11::mp_contains<variant<T...>, U>::value, "The type must be present in the list of variant alternatives" );
return v && holds_alternative<U>( *v )? detail::get_if_impl<U>( *v ): 0;
}
//
@@ -549,24 +625,34 @@ template<class T1, class... T> union variant_storage_impl<mp11::mp_false, T1, T.
T1 first_;
variant_storage<T...> rest_;
#if defined(BOOST_GCC) && (__GNUC__ >= 12)
// false positive, see https://github.com/boostorg/variant2/issues/55
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward<A>(a)... )
{
}
#if defined(BOOST_GCC) && (__GNUC__ >= 12)
# pragma GCC diagnostic pop
#endif
template<std::size_t I, class... A> constexpr variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-1>(), std::forward<A>(a)... )
{
}
~variant_storage_impl()
BOOST_VARIANT2_CXX20_CONSTEXPR ~variant_storage_impl()
{
}
template<class... A> void emplace( mp11::mp_size_t<0>, A&&... a )
template<class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<0>, A&&... a )
{
::new( &first_ ) T1( std::forward<A>(a)... );
}
template<std::size_t I, class... A> void emplace( mp11::mp_size_t<I>, A&&... a )
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<I>, A&&... a )
{
rest_.emplace( mp11::mp_size_t<I-1>(), std::forward<A>(a)... );
}
@@ -606,22 +692,22 @@ template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, c
template<std::size_t I, class... A> constexpr variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), std::forward<A>(a)... ) {}
~variant_storage_impl()
BOOST_VARIANT2_CXX20_CONSTEXPR ~variant_storage_impl()
{
}
template<class... A> void emplace( mp11::mp_size_t<0>, A&&... a ) { ::new( &t0_ ) T0( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<1>, A&&... a ) { ::new( &t1_ ) T1( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<2>, A&&... a ) { ::new( &t2_ ) T2( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<3>, A&&... a ) { ::new( &t3_ ) T3( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<4>, A&&... a ) { ::new( &t4_ ) T4( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<5>, A&&... a ) { ::new( &t5_ ) T5( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<6>, A&&... a ) { ::new( &t6_ ) T6( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<7>, A&&... a ) { ::new( &t7_ ) T7( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<8>, A&&... a ) { ::new( &t8_ ) T8( std::forward<A>(a)... ); }
template<class... A> void emplace( mp11::mp_size_t<9>, A&&... a ) { ::new( &t9_ ) T9( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<0>, A&&... a ) { ::new( &t0_ ) T0( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<1>, A&&... a ) { ::new( &t1_ ) T1( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<2>, A&&... a ) { ::new( &t2_ ) T2( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<3>, A&&... a ) { ::new( &t3_ ) T3( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<4>, A&&... a ) { ::new( &t4_ ) T4( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<5>, A&&... a ) { ::new( &t5_ ) T5( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<6>, A&&... a ) { ::new( &t6_ ) T6( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<7>, A&&... a ) { ::new( &t7_ ) T7( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<8>, A&&... a ) { ::new( &t8_ ) T8( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<9>, A&&... a ) { ::new( &t9_ ) T9( std::forward<A>(a)... ); }
template<std::size_t I, class... A> void emplace( mp11::mp_size_t<I>, A&&... a )
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace( mp11::mp_size_t<I>, A&&... a )
{
rest_.emplace( mp11::mp_size_t<I-10>(), std::forward<A>(a)... );
}
@@ -674,7 +760,7 @@ template<class T1, class... T> union variant_storage_impl<mp11::mp_true, T1, T..
{
}
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<0>, A&&... a )
template<class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<0>, A&&... a )
{
::new( &first_ ) T1( std::forward<A>(a)... );
}
@@ -695,6 +781,7 @@ template<class T1, class... T> union variant_storage_impl<mp11::mp_true, T1, T..
# pragma GCC diagnostic ignored "-Wuninitialized"
#endif
#endif
*this = variant_storage_impl( mp11::mp_size_t<I>(), std::forward<A>(a)... );
#if defined(BOOST_GCC) && (__GNUC__ >= 7)
@@ -742,16 +829,16 @@ template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, c
template<std::size_t I, class... A> constexpr variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), std::forward<A>(a)... ) {}
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<0>, A&&... a ) { ::new( &t0_ ) T0( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<1>, A&&... a ) { ::new( &t1_ ) T1( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<2>, A&&... a ) { ::new( &t2_ ) T2( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<3>, A&&... a ) { ::new( &t3_ ) T3( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<4>, A&&... a ) { ::new( &t4_ ) T4( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<5>, A&&... a ) { ::new( &t5_ ) T5( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<6>, A&&... a ) { ::new( &t6_ ) T6( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<7>, A&&... a ) { ::new( &t7_ ) T7( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<8>, A&&... a ) { ::new( &t8_ ) T8( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<9>, A&&... a ) { ::new( &t9_ ) T9( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<0>, A&&... a ) { ::new( &t0_ ) T0( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<1>, A&&... a ) { ::new( &t1_ ) T1( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<2>, A&&... a ) { ::new( &t2_ ) T2( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<3>, A&&... a ) { ::new( &t3_ ) T3( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<4>, A&&... a ) { ::new( &t4_ ) T4( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<5>, A&&... a ) { ::new( &t5_ ) T5( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<6>, A&&... a ) { ::new( &t6_ ) T6( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<7>, A&&... a ) { ::new( &t7_ ) T7( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<8>, A&&... a ) { ::new( &t8_ ) T8( std::forward<A>(a)... ); }
template<class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<9>, A&&... a ) { ::new( &t9_ ) T9( std::forward<A>(a)... ); }
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_size_t<I>, A&&... a )
{
@@ -890,7 +977,7 @@ template<class... T> struct variant_base_impl<true, true, T...>
}
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
template<class I, class... A> BOOST_CXX14_CONSTEXPR void _replace( I, A&&... a )
{
::new( &st_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
@@ -974,7 +1061,7 @@ template<class... T> struct variant_base_impl<true, false, T...>
}
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
template<class I, class... A> BOOST_CXX14_CONSTEXPR void _replace( I, A&&... a )
{
::new( &st_[ 0 ] ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
@@ -1042,7 +1129,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
}
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
template<class I, class... A> BOOST_CXX14_CONSTEXPR void _replace( I, A&&... a )
{
::new( &st_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
@@ -1059,14 +1146,25 @@ template<class... T> struct variant_base_impl<false, true, T...>
{
variant_base_impl * this_;
template<class I> void operator()( I ) const noexcept
template<class I> BOOST_CXX14_CONSTEXPR void operator()( I ) const noexcept
{
using U = mp11::mp_at<mp11::mp_list<none, T...>, I>;
#if defined(BOOST_GCC) && (__GNUC__ >= 12)
// false positive, see https://github.com/boostorg/variant2/issues/55
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
this_->st_.get( I() ).~U();
#if defined(BOOST_GCC) && (__GNUC__ >= 12)
# pragma GCC diagnostic pop
#endif
}
};
void _destroy() noexcept
BOOST_CXX14_CONSTEXPR void _destroy() noexcept
{
if( ix_ > 0 )
{
@@ -1074,7 +1172,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
}
}
~variant_base_impl() noexcept
BOOST_VARIANT2_CXX20_CONSTEXPR ~variant_base_impl() noexcept
{
_destroy();
}
@@ -1102,7 +1200,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
return st_.get( mp11::mp_size_t<I+1>() );
}
template<std::size_t I, class... A> void emplace( A&&... a )
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace( A&&... a )
{
std::size_t const J = I+1;
@@ -1110,8 +1208,18 @@ template<class... T> struct variant_base_impl<false, true, T...>
static_assert( std::is_nothrow_move_constructible<U>::value, "Logic error: U must be nothrow move constructible" );
#if defined(BOOST_GCC) && (__GNUC__ >= 12)
// false positive, see https://github.com/boostorg/variant2/issues/55
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
U tmp( std::forward<A>(a)... );
#if defined(BOOST_GCC) && (__GNUC__ >= 12)
# pragma GCC diagnostic pop
#endif
_destroy();
st_.emplace( mp11::mp_size_t<J>(), std::move(tmp) );
@@ -1182,7 +1290,7 @@ template<class... T> struct variant_base_impl<false, false, T...>
#endif
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
template<class I, class... A> BOOST_CXX14_CONSTEXPR void _replace( I, A&&... a )
{
::new( &storage( 0 ) ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
@@ -1200,19 +1308,19 @@ template<class... T> struct variant_base_impl<false, false, T...>
variant_base_impl * this_;
unsigned i2_;
template<class I> void operator()( I ) const noexcept
template<class I> BOOST_CXX14_CONSTEXPR void operator()( I ) const noexcept
{
using U = mp11::mp_at<mp11::mp_list<none, T...>, I>;
this_->storage( i2_ ).get( I() ).~U();
}
};
void _destroy() noexcept
BOOST_CXX14_CONSTEXPR void _destroy() noexcept
{
mp11::mp_with_index<1 + sizeof...(T)>( ix_ / 2, _destroy_L1{ this, static_cast<unsigned>( ix_ & 1 ) } );
}
~variant_base_impl() noexcept
BOOST_VARIANT2_CXX20_CONSTEXPR ~variant_base_impl() noexcept
{
_destroy();
}
@@ -1242,7 +1350,7 @@ template<class... T> struct variant_base_impl<false, false, T...>
return storage( ix_ & 1 ).get( mp11::mp_size_t<I+1>() );
}
template<std::size_t I, class... A> void emplace( A&&... a )
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace( A&&... a )
{
std::size_t const J = I+1;
@@ -1403,7 +1511,7 @@ private:
variant_base * this_;
variant_base const & r;
template<class I> void operator()( I i ) const
template<class I> BOOST_CXX14_CONSTEXPR void operator()( I i ) const
{
this_->_replace( i, r._get_impl( i ) );
}
@@ -1411,7 +1519,7 @@ private:
public:
variant_cc_base_impl( variant_cc_base_impl const& r )
BOOST_CXX14_CONSTEXPR variant_cc_base_impl( variant_cc_base_impl const& r )
noexcept( mp11::mp_all<std::is_nothrow_copy_constructible<T>...>::value )
: variant_base()
{
@@ -1483,7 +1591,7 @@ private:
variant_base * this_;
variant_base const & r;
template<class I> void operator()( I i ) const
template<class I> BOOST_CXX14_CONSTEXPR void operator()( I i ) const
{
this_->template emplace<I::value>( r._get_impl( i ) );
}
@@ -1557,7 +1665,7 @@ private:
variant_base * this_;
variant_base & r;
template<class I> void operator()( I i ) const
template<class I> BOOST_CXX14_CONSTEXPR void operator()( I i ) const
{
this_->_replace( i, std::move( r._get_impl( i ) ) );
}
@@ -1565,7 +1673,7 @@ private:
public:
variant_mc_base_impl( variant_mc_base_impl && r )
BOOST_CXX14_CONSTEXPR variant_mc_base_impl( variant_mc_base_impl && r )
noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value )
{
mp11::mp_with_index<sizeof...(T)>( r.index(), L2{ this, r } );
@@ -1636,7 +1744,7 @@ private:
variant_base * this_;
variant_base & r;
template<class I> void operator()( I i ) const
template<class I> BOOST_CXX14_CONSTEXPR void operator()( I i ) const
{
this_->template emplace<I::value>( std::move( r._get_impl( i ) ) );
}
@@ -1644,7 +1752,7 @@ private:
public:
variant_ma_base_impl& operator=( variant_ma_base_impl && r )
BOOST_CXX14_CONSTEXPR variant_ma_base_impl& operator=( variant_ma_base_impl && r )
noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value )
{
mp11::mp_with_index<sizeof...(T)>( r.index(), L4{ this, r } );
@@ -1680,7 +1788,7 @@ public:
class Ud = typename std::decay<U>::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,
#if BOOST_WORKAROUND(BOOST_MSVC, < 1950)
#if BOOST_WORKAROUND(BOOST_MSVC, < 1960)
class V = mp11::mp_apply_q< mp11::mp_bind_front<detail::resolve_overload_type, U&&>, variant >,
@@ -1790,7 +1898,7 @@ private:
variant * this_;
variant & r;
template<class I> void operator()( I i ) const
template<class I> BOOST_CXX14_CONSTEXPR void operator()( I i ) const
{
using std::swap;
swap( this_->_get_impl( i ), r._get_impl( i ) );
@@ -1799,7 +1907,7 @@ private:
public:
void swap( variant& r ) noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>..., detail::is_nothrow_swappable<T>...>::value )
BOOST_CXX14_CONSTEXPR void swap( variant& r ) noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>..., detail::is_nothrow_swappable<T>...>::value )
{
if( index() == r.index() )
{
@@ -1826,7 +1934,7 @@ private:
variant_base * this_;
variant<U...> const & r;
template<class I> void operator()( I i ) const
template<class I> BOOST_CXX14_CONSTEXPR void operator()( I i ) const
{
using J = mp11::mp_find<mp11::mp_list<T...>, mp11::mp_at<mp11::mp_list<U...>, I>>;
this_->_replace( J{}, r._get_impl( i ) );
@@ -1837,7 +1945,7 @@ public:
template<class... U,
class E2 = mp11::mp_if<mp11::mp_all<std::is_copy_constructible<U>..., mp11::mp_contains<mp11::mp_list<T...>, U>...>, void> >
variant( variant<U...> const& r )
BOOST_CXX14_CONSTEXPR variant( variant<U...> const& r )
noexcept( mp11::mp_all<std::is_nothrow_copy_constructible<U>...>::value )
{
mp11::mp_with_index<sizeof...(U)>( r.index(), L6<U...>{ this, r } );
@@ -1850,7 +1958,7 @@ private:
variant_base * this_;
variant<U...> & r;
template<class I> void operator()( I i ) const
template<class I> BOOST_CXX14_CONSTEXPR void operator()( I i ) const
{
using J = mp11::mp_find<mp11::mp_list<T...>, mp11::mp_at<mp11::mp_list<U...>, I>>;
this_->_replace( J{}, std::move( r._get_impl( i ) ) );
@@ -1861,7 +1969,7 @@ public:
template<class... U,
class E2 = mp11::mp_if<mp11::mp_all<std::is_move_constructible<U>..., mp11::mp_contains<mp11::mp_list<T...>, U>...>, void> >
variant( variant<U...> && r )
BOOST_CXX14_CONSTEXPR variant( variant<U...> && r )
noexcept( mp11::mp_all<std::is_nothrow_move_constructible<U>...>::value )
{
mp11::mp_with_index<sizeof...(U)>( r.index(), L7<U...>{ this, r } );
@@ -1887,7 +1995,7 @@ private:
{
variant * this_;
template<class I> variant<U...> operator()( I i ) const
template<class I> BOOST_CXX14_CONSTEXPR variant<U...> operator()( I i ) const
{
using J = mp11::mp_find<mp11::mp_list<U...>, mp11::mp_at<mp11::mp_list<T...>, I>>;
return this_->_subset_impl<U...>( J{}, this_->_get_impl( i ) );
@@ -1909,7 +2017,7 @@ private:
{
variant const * this_;
template<class I> variant<U...> operator()( I i ) const
template<class I> BOOST_CXX14_CONSTEXPR variant<U...> operator()( I i ) const
{
using J = mp11::mp_find<mp11::mp_list<U...>, mp11::mp_at<mp11::mp_list<T...>, I>>;
return this_->_subset_impl<U...>( J{}, this_->_get_impl( i ) );
@@ -1931,7 +2039,7 @@ private:
{
variant * this_;
template<class I> variant<U...> operator()( I i ) const
template<class I> BOOST_CXX14_CONSTEXPR variant<U...> operator()( I i ) const
{
using J = mp11::mp_find<mp11::mp_list<U...>, mp11::mp_at<mp11::mp_list<T...>, I>>;
return this_->_subset_impl<U...>( J{}, std::move( this_->_get_impl( i ) ) );
@@ -1957,7 +2065,7 @@ private:
{
variant const * this_;
template<class I> variant<U...> operator()( I i ) const
template<class I> BOOST_CXX14_CONSTEXPR variant<U...> operator()( I i ) const
{
using J = mp11::mp_find<mp11::mp_list<U...>, mp11::mp_at<mp11::mp_list<T...>, I>>;
return this_->_subset_impl<U...>( J{}, std::move( this_->_get_impl( i ) ) );
@@ -2293,7 +2401,7 @@ template<class R = detail::deduced, class F, class V1, class V2, class... V> con
// specialized algorithms
template<class... T,
class E = typename std::enable_if<mp11::mp_all<std::is_move_constructible<T>..., detail::is_swappable<T>...>::value>::type>
void swap( variant<T...> & v, variant<T...> & w )
BOOST_CXX14_CONSTEXPR void swap( variant<T...> & v, variant<T...> & w )
noexcept( noexcept(v.swap(w)) )
{
v.swap( w );

View File

@@ -6,6 +6,6 @@ include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST)
if(HAVE_BOOST_TEST)
boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::variant2 Boost::core Boost::container_hash)
boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::variant2 Boost::core Boost::container_hash Boost::system)
endif()

View File

@@ -1,14 +1,8 @@
# Boost.Variant2 Library Test Jamfile
#
# Copyright 2015-2019 Peter Dimov
#
# Copyright 2015-2026 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
import testing ;
import-search /boost/config/checks ;
import config : requires ;
project
: default-build
@@ -33,54 +27,54 @@ run variant_size.cpp ;
run variant_alternative.cpp ;
run variant_holds_alternative.cpp ;
compile variant_holds_alternative_cx.cpp : <toolset>msvc-14.0:<build>no ;
compile variant_holds_alternative_cx.cpp ;
run variant_get_by_index.cpp ;
compile variant_get_by_index_cx.cpp : <toolset>msvc-14.0:<build>no ;
compile variant_get_by_index_cx.cpp ;
run variant_get_by_type.cpp ;
compile variant_get_by_type_cx.cpp : <toolset>msvc-14.0:<build>no ;
compile variant_get_by_type_cx.cpp ;
run variant_default_construct.cpp ;
compile variant_default_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
compile variant_default_construct_cx.cpp ;
run variant_copy_construct.cpp ;
compile variant_copy_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
compile variant_copy_construct_cx.cpp ;
run variant_move_construct.cpp ;
compile variant_move_construct_cx.cpp : [ requires cxx14_constexpr ] ;
compile variant_move_construct_cx.cpp ;
run variant_value_construct.cpp ;
compile variant_value_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
compile variant_value_construct_cx.cpp ;
run variant_in_place_index_construct.cpp ;
compile variant_in_place_index_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
compile variant_in_place_index_construct_cx.cpp ;
run variant_in_place_type_construct.cpp ;
compile variant_in_place_type_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
compile variant_in_place_type_construct_cx.cpp ;
run variant_copy_assign.cpp ;
compile variant_copy_assign_cx.cpp : [ requires cxx14_constexpr ] <toolset>gcc-5:<build>no <toolset>gcc-6:<build>no ;
compile variant_copy_assign_cx.cpp ;
run variant_move_assign.cpp ;
compile variant_move_assign_cx.cpp : [ requires cxx14_constexpr ] <toolset>gcc-5:<build>no <toolset>gcc-6:<build>no ;
compile variant_move_assign_cx.cpp ;
run variant_value_assign.cpp ;
compile variant_value_assign_cx.cpp : [ requires cxx14_constexpr ] ;
compile variant_value_assign_cx.cpp ;
run variant_emplace_index.cpp ;
compile variant_emplace_index_cx.cpp : [ requires cxx14_constexpr ] ;
compile variant_emplace_index_cx.cpp ;
run variant_emplace_type.cpp ;
compile variant_emplace_type_cx.cpp : [ requires cxx14_constexpr ] ;
compile variant_emplace_type_cx.cpp ;
run variant_swap.cpp ;
run variant_eq_ne.cpp ;
compile variant_eq_ne_cx.cpp : [ requires cxx14_constexpr ] ;
compile variant_eq_ne_cx.cpp ;
run variant_lt_gt.cpp ;
compile variant_lt_gt_cx.cpp : [ requires cxx14_constexpr ] ;
compile variant_lt_gt_cx.cpp ;
run variant_destroy.cpp ;
run variant_visit.cpp ;
@@ -103,10 +97,10 @@ local NX =
;
run variant_get_by_index.cpp throw_exception.cpp : : : $(NX) : variant_get_by_index_nx ;
compile variant_get_by_index_cx.cpp : $(NX) <toolset>msvc-14.0:<build>no : variant_get_by_index_cx_nx ;
compile variant_get_by_index_cx.cpp : $(NX) : variant_get_by_index_cx_nx ;
run variant_get_by_type.cpp throw_exception.cpp : : : $(NX) : variant_get_by_type_nx ;
compile variant_get_by_type_cx.cpp : $(NX) <toolset>msvc-14.0:<build>no : variant_get_by_type_cx_nx ;
compile variant_get_by_type_cx.cpp : $(NX) : variant_get_by_type_cx_nx ;
run variant_subset.cpp throw_exception.cpp : : : $(NX) : variant_subset_nx ;
@@ -117,7 +111,12 @@ run variant_special.cpp ;
run variant_visit_derived.cpp ;
run variant_many_types.cpp ;
# These two tests require /bigobj under GCC/Windows and CMake/VS2022 (for some reason)
run variant_many_types.cpp : : :
<toolset>gcc,<target-os>windows:<variant>release
<toolset>gcc,<target-os>cygwin:<variant>release
;
run variant_visit_r.cpp : : :
<toolset>gcc,<target-os>windows:<variant>release
@@ -131,7 +130,13 @@ run variant_visit_by_index.cpp ;
run variant_ostream_insert.cpp ;
run is_output_streamable.cpp ;
local JSON = <library>/boost/json//boost_json/<warnings>off "<toolset>msvc-14.0:<build>no" "<toolset>msvc-14.2:<cxxflags>-wd5104" "<undefined-sanitizer>norecover:<link>static" ;
local JSON =
<library>/boost/json//boost_json/<warnings>off
"<toolset>msvc-14.0:<build>no"
"<toolset>msvc-14.2:<cxxflags>-wd5104"
"<undefined-sanitizer>norecover:<link>static"
"<toolset>gcc-4.9:<build>no"
;
run variant_json_value_from.cpp : : : $(JSON) ;
run variant_json_value_to.cpp : : : $(JSON) ;
@@ -140,9 +145,9 @@ compile variant_uses_double_storage.cpp ;
run variant_derived_construct2.cpp ;
compile variant_visit_cx.cpp : [ requires cxx14_constexpr ] ;
compile variant_visit_cx_2.cpp : [ requires cxx14_constexpr ] ;
compile variant_visit_r_cx.cpp : [ requires cxx14_constexpr ] ;
compile variant_visit_cx.cpp ;
compile variant_visit_cx_2.cpp ;
compile variant_visit_r_cx.cpp ;
local index-type-reqs =
@@ -157,3 +162,21 @@ for local list-size in $(list-sizes)
{
run variant_index_type.cpp : : : $(index-type-reqs) <define>LIST_SIZE=$(list-size) : variant_index_type_$(list-size) ;
}
compile variant_default_construct_cx_2.cpp ;
compile variant_default_construct_cx_3.cpp ;
compile variant_default_construct_cx_4.cpp ;
compile variant_default_construct_cx_5.cpp ;
compile variant_value_construct_cx_2.cpp ;
compile variant_value_construct_cx_3.cpp ;
compile variant_value_construct_cx_4.cpp ;
# GCC 12+ false positive -Wmaybe-uninitialized with non-trivially-copyable types
run variant_issue_55.cpp
: : :
<library>/boost/system//boost_system
# clang-cl 32 bit fails with an assertion in mp_with_index, likely due to a codegen bug
"<toolset>clang-win,<address-model>32:<build>no"
;

View File

@@ -1,12 +1,22 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#elif defined(BOOST_GCC) && BOOST_GCC < 70000
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_GCC < 70000" )
int main() {}
#else
using namespace boost::variant2;
@@ -33,26 +43,26 @@ enum E
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
template<class V, class T, class A> constexpr T test( A const& a )
template<class V, std::size_t I, class A> constexpr variant_alternative_t<I, V> test( A const& a )
{
V v;
v = a;
return get<T>(v);
return get<I>(v);
}
int main()
{
{
constexpr variant<int> v( 1 );
constexpr auto w = test<variant<int>, int>( v );
constexpr auto w = test<variant<int>, 0>( v );
STATIC_ASSERT( w == 1 );
}
{
constexpr variant<X> v( 1 );
constexpr auto w = test<variant<X>, X>( v );
constexpr auto w = test<variant<X>, 0>( v );
STATIC_ASSERT( w == 1 );
}
@@ -61,7 +71,7 @@ int main()
{
constexpr variant<Y> v( 1 );
constexpr auto w = test<variant<Y>, Y>( v );
constexpr auto w = test<variant<Y>, 0>( v );
STATIC_ASSERT( w == 1 );
}
@@ -69,31 +79,31 @@ int main()
{
constexpr variant<int, float> v( 1 );
constexpr auto w = test<variant<int, float>, int>( v );
constexpr auto w = test<variant<int, float>, 0>( v );
STATIC_ASSERT( w == 1 );
}
{
constexpr variant<int, float> v( 3.0f );
constexpr auto w = test<variant<int, float>, float>( v );
constexpr auto w = test<variant<int, float>, 1>( v );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr variant<int, int, float> v( 3.0f );
constexpr auto w = test<variant<int, int, float>, float>( v );
constexpr auto w = test<variant<int, int, float>, 2>( v );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr variant<E, E, X> v( 1 );
constexpr auto w = test<variant<E, E, X>, X>( v );
constexpr auto w = test<variant<E, E, X>, 2>( v );
STATIC_ASSERT( w == 1 );
}
{
constexpr variant<int, int, float, float, X> v( X(1) );
constexpr auto w = test<variant<int, int, float, float, X>, X>( v );
constexpr auto w = test<variant<int, int, float, float, X>, 4>( v );
STATIC_ASSERT( w == 1 );
}
@@ -102,15 +112,17 @@ int main()
{
constexpr variant<E, E, Y> v( 1 );
constexpr auto w = test<variant<E, E, Y>, Y>( v );
constexpr auto w = test<variant<E, E, Y>, 2>( v );
STATIC_ASSERT( w == 1 );
}
{
constexpr variant<int, int, float, float, Y> v( Y(1) );
constexpr auto w = test<variant<int, int, float, float, Y>, Y>( v );
constexpr auto w = test<variant<int, int, float, float, Y>, 4>( v );
STATIC_ASSERT( w == 1 );
}
#endif
}
#endif

View File

@@ -45,7 +45,7 @@ void test()
variant<Y1, Y2> v1( in_place_type_t<Y1>{} );
variant<Y1, Y2> v2( in_place_type_t<Y2>{} );
BOOST_TEST_THROWS( v1 = v2, std::runtime_error )
BOOST_TEST_THROWS( v1 = v2, std::runtime_error );
}
int main()

View File

@@ -1,12 +1,17 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC < 1910" )
int main() {}
#else
using namespace boost::variant2;
@@ -33,22 +38,22 @@ enum E
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
template<class T, class V> constexpr T test( V const v )
template<std::size_t I, class V> constexpr variant_alternative_t<I, V> test( V const v )
{
return get<T>( v );
return get<I>( v );
}
int main()
{
{
constexpr variant<int> v( 1 );
constexpr auto w = test<int>( v );
constexpr auto w = test<0>( v );
STATIC_ASSERT( w == 1 );
}
{
constexpr variant<X> v( 1 );
constexpr auto w = test<X>( v );
constexpr auto w = test<0>( v );
STATIC_ASSERT( w == 1 );
}
@@ -57,7 +62,7 @@ int main()
{
constexpr variant<Y> v( 1 );
constexpr auto w = test<Y>( v );
constexpr auto w = test<0>( v );
STATIC_ASSERT( w == 1 );
}
@@ -65,31 +70,31 @@ int main()
{
constexpr variant<int, float> v( 1 );
constexpr auto w = test<int>( v );
constexpr auto w = test<0>( v );
STATIC_ASSERT( w == 1 );
}
{
constexpr variant<int, float> v( 3.0f );
constexpr auto w = test<float>( v );
constexpr auto w = test<1>( v );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr variant<int, int, float> v( 3.0f );
constexpr auto w = test<float>( v );
constexpr auto w = test<2>( v );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr variant<E, E, X> v( 1 );
constexpr auto w = test<X>( v );
constexpr auto w = test<2>( v );
STATIC_ASSERT( w == 1 );
}
{
constexpr variant<int, int, float, float, X> v( X(1) );
constexpr auto w = test<X>( v );
constexpr auto w = test<4>( v );
STATIC_ASSERT( w == 1 );
}
@@ -98,15 +103,17 @@ int main()
{
constexpr variant<E, E, Y> v( 1 );
constexpr auto w = test<Y>( v );
constexpr auto w = test<2>( v );
STATIC_ASSERT( w == 1 );
}
{
constexpr variant<int, int, float, float, Y> v( Y(1) );
constexpr auto w = test<Y>( v );
constexpr auto w = test<4>( v );
STATIC_ASSERT( w == 1 );
}
#endif
}
#endif

View File

@@ -1,12 +1,17 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC < 1910" )
int main() {}
#else
using namespace boost::variant2;
@@ -49,3 +54,5 @@ int main()
STATIC_ASSERT( get<0>(v) == 0 );
}
}
#endif

View File

@@ -0,0 +1,32 @@
// Copyright 2025 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/config/pragma_message.hpp>
#if !defined(__cpp_constexpr_dynamic_alloc) || __cpp_constexpr_dynamic_alloc < 201907L
BOOST_PRAGMA_MESSAGE("Skipping constexpr destructor test because __cpp_constexpr_dynamic_alloc < 201907L")
int main() {}
#else
using namespace boost::variant2;
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
struct X
{
constexpr ~X() {}
};
int main()
{
constexpr variant<int, X> v;
STATIC_ASSERT( v.index() == 0 );
STATIC_ASSERT( get<0>(v) == 0 );
}
#endif

View File

@@ -0,0 +1,37 @@
// Copyright 2025 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/config/pragma_message.hpp>
#if !defined(__cpp_constexpr_dynamic_alloc) || __cpp_constexpr_dynamic_alloc < 201907L
BOOST_PRAGMA_MESSAGE("Skipping constexpr destructor test because __cpp_constexpr_dynamic_alloc < 201907L")
int main() {}
#elif defined(BOOST_CLANG) && BOOST_CLANG_VERSION < 180000
BOOST_PRAGMA_MESSAGE("Skipping constexpr destructor test because BOOST_CLANG_VERSION < 180000")
int main() {}
#else
using namespace boost::variant2;
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
struct X
{
~X() {}
};
int main()
{
constexpr variant<int, X> v;
STATIC_ASSERT( v.index() == 0 );
STATIC_ASSERT( get<0>(v) == 0 );
}
#endif

View File

@@ -0,0 +1,33 @@
// Copyright 2025 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/config/pragma_message.hpp>
#include <string>
#if !defined(__cpp_constexpr_dynamic_alloc) || __cpp_constexpr_dynamic_alloc < 201907L
BOOST_PRAGMA_MESSAGE("Skipping constexpr destructor test because __cpp_constexpr_dynamic_alloc < 201907L")
int main() {}
#elif defined(BOOST_CLANG) && BOOST_CLANG_VERSION < 180000
BOOST_PRAGMA_MESSAGE("Skipping constexpr destructor test because BOOST_CLANG_VERSION < 180000")
int main() {}
#else
using namespace boost::variant2;
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
int main()
{
constexpr variant<int, std::string> v;
STATIC_ASSERT( v.index() == 0 );
STATIC_ASSERT( get<0>(v) == 0 );
}
#endif

View File

@@ -0,0 +1,49 @@
// Copyright 2025 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/config/pragma_message.hpp>
#if !defined(__cpp_constexpr_dynamic_alloc) || __cpp_constexpr_dynamic_alloc < 201907L
BOOST_PRAGMA_MESSAGE("Skipping constexpr destructor test because __cpp_constexpr_dynamic_alloc < 201907L")
int main() {}
#elif defined(BOOST_MSVC) && BOOST_MSVC < 1960
BOOST_PRAGMA_MESSAGE("Skipping constexpr destructor test because BOOST_MSVC < 1960")
int main() {}
#elif defined(BOOST_CLANG) && BOOST_CLANG_VERSION < 180000
BOOST_PRAGMA_MESSAGE("Skipping constexpr destructor test because BOOST_CLANG_VERSION < 180000")
int main() {}
#else
using namespace boost::variant2;
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
struct X
{
};
struct Y
{
constexpr ~Y() {}
};
struct Z
{
~Z() {}
};
int main()
{
constexpr variant<X, Y, Z> v;
STATIC_ASSERT( v.index() == 0 );
}
#endif

View File

@@ -1,12 +1,17 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
using namespace boost::variant2;
@@ -134,3 +139,5 @@ int main()
#endif
}
#endif

View File

@@ -1,12 +1,17 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
using namespace boost::variant2;
@@ -28,24 +33,24 @@ struct Y
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
template<class V, class T, class A> constexpr A test( A const& a )
template<class V, std::size_t I, class A, class T = variant_alternative_t<I, V>> constexpr T test( A const& a )
{
V v;
v.template emplace<T>( a );
return get<T>(v);
return get<I>(v);
}
int main()
{
{
constexpr auto w = test<variant<int>, int>( 1 );
constexpr auto w = test<variant<int>, 0>( 1 );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<variant<X>, X>( 1 );
constexpr auto w = test<variant<X>, 0>( 1 );
STATIC_ASSERT( w == 1 );
}
@@ -53,29 +58,29 @@ int main()
#else
{
constexpr auto w = test<variant<Y>, Y>( 1 );
constexpr auto w = test<variant<Y>, 0>( 1 );
STATIC_ASSERT( w == 1 );
}
#endif
{
constexpr auto w = test<variant<int, float>, int>( 1 );
constexpr auto w = test<variant<int, float>, 0>( 1 );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<variant<int, float>, float>( 3.0f );
constexpr auto w = test<variant<int, float>, 1>( 3.0f );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr auto w = test<variant<int, int, float>, float>( 3.0f );
constexpr auto w = test<variant<int, int, float>, 2>( 3.0f );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr auto w = test<variant<int, int, float, float, X>, X>( 1 );
constexpr auto w = test<variant<int, int, float, float, X>, 4>( 1 );
STATIC_ASSERT( w == 1 );
}
@@ -83,9 +88,11 @@ int main()
#else
{
constexpr auto w = test<variant<int, int, float, float, Y>, Y>( 1 );
constexpr auto w = test<variant<int, int, float, float, Y>, 4>( 1 );
STATIC_ASSERT( w == 1 );
}
#endif
}
#endif

View File

@@ -1,24 +1,26 @@
// Copyright 2017, 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
#include <boost/variant2/variant.hpp>
using namespace boost::variant2;
#if !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR)
#include <boost/mp11.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping constexpr op==, op!= test because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined")
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#elif !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE("Skipping constexpr op==, op!= test because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined")
int main() {}
#else
using namespace boost::variant2;
struct X
{
};

View File

@@ -1,13 +1,17 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC < 1910" )
int main() {}
#else
using namespace boost::variant2;
@@ -94,3 +98,5 @@ int main()
STATIC_ASSERT_IF( get_if<2>(&v) == &get<2>(v) );
}
}
#endif

View File

@@ -1,10 +1,6 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#if defined( __clang__ ) && defined( __has_warning )
# if __has_warning( "-Wdeprecated-volatile" )
@@ -217,6 +213,9 @@ int main()
BOOST_TEST_EQ( get<int>(v), 0 );
BOOST_TEST_EQ( get_if<int>(&v), &get<int>(v) );
BOOST_TEST_THROWS( get<float>(v), bad_variant_access );
BOOST_TEST_EQ( get_if<float>(&v), nullptr );
BOOST_TEST_EQ( get<int>(std::move(v)), 0 );
}
@@ -226,6 +225,9 @@ int main()
BOOST_TEST_EQ( get<int>(v), 0 );
BOOST_TEST_EQ( get_if<int>(&v), &get<int>(v) );
BOOST_TEST_THROWS( get<float>(v), bad_variant_access );
BOOST_TEST_EQ( get_if<float>(&v), nullptr );
BOOST_TEST_EQ( get<int>(std::move(v)), 0 );
}
@@ -235,6 +237,9 @@ int main()
BOOST_TEST_EQ( get<int>(v), 1 );
BOOST_TEST_EQ( get_if<int>(&v), &get<int>(v) );
BOOST_TEST_THROWS( get<float>(v), bad_variant_access );
BOOST_TEST_EQ( get_if<float>(&v), nullptr );
BOOST_TEST_EQ( get<int>(std::move(v)), 1 );
}
@@ -244,12 +249,18 @@ int main()
BOOST_TEST_EQ( get<int>(v), 1 );
BOOST_TEST_EQ( get_if<int>(&v), &get<int>(v) );
BOOST_TEST_THROWS( get<float>(v), bad_variant_access );
BOOST_TEST_EQ( get_if<float>(&v), nullptr );
BOOST_TEST_EQ( get<int>(std::move(v)), 1 );
}
{
variant<int, int, float> v( 3.14f );
BOOST_TEST_THROWS( get<int>(v), bad_variant_access );
BOOST_TEST_EQ( get_if<int>(&v), nullptr );
BOOST_TEST_EQ( get<float>(v), 3.14f );
BOOST_TEST_EQ( get_if<float>(&v), &get<float>(v) );
@@ -259,6 +270,9 @@ int main()
{
variant<int, int, float> const v( 3.14f );
BOOST_TEST_THROWS( get<int>(v), bad_variant_access );
BOOST_TEST_EQ( get_if<int>(&v), nullptr );
BOOST_TEST_EQ( get<float>(v), 3.14f );
BOOST_TEST_EQ( get_if<float>(&v), &get<float>(v) );
@@ -301,11 +315,13 @@ int main()
{
variant<int, int, float> * p = 0;
BOOST_TEST_EQ( get_if<int>(p), nullptr );
BOOST_TEST_EQ( get_if<float>(p), nullptr );
}
{
variant<int, int, float> const * p = 0;
BOOST_TEST_EQ( get_if<int>(p), nullptr );
BOOST_TEST_EQ( get_if<float>(p), nullptr );
}

View File

@@ -1,13 +1,18 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/mp11.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE("Test skipped because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined")
int main() {}
#else
using namespace boost::variant2;
@@ -70,6 +75,7 @@ int main()
STATIC_ASSERT( get<int>(v) == 0 );
STATIC_ASSERT_IF( get_if<int>(&v) == &get<int>(v) );
STATIC_ASSERT_IF( get_if<float>(&v) == nullptr );
}
{
@@ -78,6 +84,7 @@ int main()
STATIC_ASSERT( get<int>(v) == 1 );
STATIC_ASSERT_IF( get_if<int>(&v) == &get<int>(v) );
STATIC_ASSERT_IF( get_if<float>(&v) == nullptr );
}
{
@@ -85,6 +92,9 @@ int main()
STATIC_ASSERT( get<float>(v) == (float)3.14f );
STATIC_ASSERT_IF( get_if<int>(&v) == nullptr );
STATIC_ASSERT_IF( get_if<float>(&v) == &get<float>(v) );
}
}
#endif

View File

@@ -1,10 +1,6 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/core/lightweight_test.hpp>
@@ -34,13 +30,27 @@ int main()
{
variant<int, float, float> v;
BOOST_TEST( holds_alternative<int>( v ) );
BOOST_TEST( !holds_alternative<float>( v ) );
}
{
variant<int, int, float> v( 3.14f );
BOOST_TEST( !holds_alternative<int>( v ) );
BOOST_TEST( holds_alternative<float>( v ) );
}
{
variant<int, int, float> v( in_place_index_t<0>{} );
BOOST_TEST( holds_alternative<int>( v ) );
BOOST_TEST( !holds_alternative<float>( v ) );
}
{
variant<int, int, float> v( in_place_index_t<1>{} );
BOOST_TEST( holds_alternative<int>( v ) );
BOOST_TEST( !holds_alternative<float>( v ) );
}
{
variant<int, float, std::string> v;
BOOST_TEST( holds_alternative<int>( v ) );
@@ -64,15 +74,31 @@ int main()
{
variant<int, int, float, std::string> v( 3.14f );
BOOST_TEST( !holds_alternative<int>( v ) );
BOOST_TEST( holds_alternative<float>( v ) );
BOOST_TEST( !holds_alternative<std::string>( v ) );
}
{
variant<int, int, float, std::string> v( "text" );
BOOST_TEST( !holds_alternative<int>( v ) );
BOOST_TEST( !holds_alternative<float>( v ) );
BOOST_TEST( holds_alternative<std::string>( v ) );
}
{
variant<int, int, float, std::string> v( in_place_index_t<0>{} );
BOOST_TEST( holds_alternative<int>( v ) );
BOOST_TEST( !holds_alternative<float>( v ) );
BOOST_TEST( !holds_alternative<std::string>( v ) );
}
{
variant<int, int, float, std::string> v( in_place_index_t<1>{} );
BOOST_TEST( holds_alternative<int>( v ) );
BOOST_TEST( !holds_alternative<float>( v ) );
BOOST_TEST( !holds_alternative<std::string>( v ) );
}
return boost::report_errors();
}

View File

@@ -1,12 +1,17 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC < 1910" )
int main() {}
#else
using namespace boost::variant2;
@@ -34,10 +39,20 @@ int main()
{
constexpr variant<int, float, float> v;
STATIC_ASSERT( holds_alternative<int>( v ) );
STATIC_ASSERT( !holds_alternative<float>( v ) );
}
{
constexpr variant<int, int, float> v( 3.14f );
STATIC_ASSERT( !holds_alternative<int>( v ) );
STATIC_ASSERT( holds_alternative<float>( v ) );
}
{
constexpr variant<int, int, float> v;
STATIC_ASSERT( holds_alternative<int>( v ) );
STATIC_ASSERT( !holds_alternative<float>( v ) );
}
}
#endif

View File

@@ -1,14 +1,18 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC < 1910" )
int main() {}
#else
using namespace boost::variant2;
@@ -119,3 +123,5 @@ int main()
#endif
}
#endif

View File

@@ -1,14 +1,18 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC < 1910" )
int main() {}
#else
using namespace boost::variant2;
@@ -118,3 +122,5 @@ int main()
#endif
}
#endif

194
test/variant_issue_55.cpp Normal file
View File

@@ -0,0 +1,194 @@
// Copyright 2025 Peter Dimov
// Copyright 2025 Vinnie Falco
//
// 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
// GCC 12+ -Wmaybe-uninitialized false positive tests
// https://github.com/boostorg/variant2/issues/55
//
// GCC 12+'s improved dataflow analysis sees code paths for all alternatives
// in mp_with_index and warns that members may be uninitialized, even though
// the variant's discriminator guarantees only initialized alternatives are
// accessed.
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <exception>
#include <string>
// Check for C++17 std::optional support
#if BOOST_CXX_VERSION >= 201703L
# include <optional>
# define BOOST_VARIANT2_TEST_HAS_OPTIONAL 1
#endif
// Check for C++20 coroutine support
#if defined(__cpp_impl_coroutine) && __cpp_impl_coroutine >= 201902L
# include <coroutine>
# define BOOST_VARIANT2_TEST_HAS_CORO 1
#endif
using result_void = boost::system::result<void, std::exception_ptr>;
using result_string = boost::system::result<std::string, std::exception_ptr>;
void testGccUninitialized()
{
// Test 1: Simple copy construction
{
result_void r1;
result_void r2(r1);
(void)r2;
}
// Test 2: Copy assignment
{
result_void r1;
result_void r2;
r2 = r1;
(void)r2;
}
#ifdef BOOST_VARIANT2_TEST_HAS_OPTIONAL
// Test 3: std::optional assignment (matches spawn pattern)
{
std::optional<result_void> opt;
opt = result_void{};
(void)opt;
}
#endif
// Test 4: Pass to function via copy
{
auto fn = [](result_void r) { (void)r; };
fn(result_void{});
}
#ifdef BOOST_VARIANT2_TEST_HAS_OPTIONAL
// Test 5: Lambda capture + optional (closest to spawn)
{
auto fn = [](result_void r) {
std::optional<result_void> opt;
opt = r;
return opt.has_value();
};
(void)fn(result_void{});
}
#endif
// Test 6: Non-void result with string (triggers string warning)
{
result_string r1;
result_string r2(r1);
(void)r2;
}
// Test 7: Assign exception to result holding value
{
result_string r1{"hello"};
r1 = std::make_exception_ptr(std::runtime_error("test"));
(void)r1;
}
#ifdef BOOST_VARIANT2_TEST_HAS_OPTIONAL
// Test 8: Optional with string result
{
std::optional<result_string> opt;
opt = result_string{};
(void)opt;
}
#endif
#ifdef BOOST_VARIANT2_TEST_HAS_CORO
// Minimal fire-and-forget coroutine for testing
struct fire_and_forget
{
struct promise_type
{
fire_and_forget get_return_object() { return {}; }
std::suspend_never initial_suspend() noexcept { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() { std::terminate(); }
};
};
// Test 9: Coroutine returning result (mimics spawn)
{
auto coro = []() -> fire_and_forget {
result_void r{};
(void)r;
co_return;
};
coro();
}
// Test 10: Coroutine with handler call (closest to actual spawn)
{
std::optional<result_void> received;
auto handler = [&](result_void r) {
received = r;
};
auto coro = [&]() -> fire_and_forget {
handler(result_void{});
co_return;
};
coro();
(void)received;
}
// Test 11: Coroutine with try/catch like spawn
{
std::optional<result_void> received;
auto handler = [&](result_void r) {
received = r;
};
auto coro = [&]() -> fire_and_forget {
try
{
handler(result_void{});
}
catch (...)
{
handler(result_void{std::current_exception()});
}
co_return;
};
coro();
(void)received;
}
// Test 12: Coroutine with string result
{
std::optional<result_string> received;
auto handler = [&](result_string r) {
received = r;
};
auto coro = [&]() -> fire_and_forget {
try
{
handler(result_string{"test"});
}
catch (...)
{
handler(result_string{std::current_exception()});
}
co_return;
};
coro();
(void)received;
}
#endif
}
int main()
{
boost::core::lwt_init();
testGccUninitialized();
return boost::report_errors();
}

View File

@@ -1,24 +1,26 @@
// Copyright 2017, 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
#include <boost/variant2/variant.hpp>
using namespace boost::variant2;
#if !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR)
#include <boost/mp11.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping constexpr op<, op<= test because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined")
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#elif !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE("Skipping constexpr op<, op<= test because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined")
int main() {}
#else
using namespace boost::variant2;
struct X
{
};

View File

@@ -1,14 +1,24 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#include <utility>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#elif defined(BOOST_GCC) && BOOST_GCC < 70000
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_GCC < 70000" )
int main() {}
#else
using namespace boost::variant2;
struct X
@@ -34,24 +44,24 @@ enum E
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
template<class V, class T, class A> constexpr T test( A&& a )
template<class V, std::size_t I, class A> constexpr variant_alternative_t<I, V> test( A&& a )
{
V v;
v = std::forward<A>(a);
return get<T>(v);
return get<I>(v);
}
int main()
{
{
constexpr auto w = test<variant<int>, int>( variant<int>( 1 ) );
constexpr auto w = test<variant<int>, 0>( variant<int>( 1 ) );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<variant<X>, X>( variant<X>( 1 ) );
constexpr auto w = test<variant<X>, 0>( variant<X>( 1 ) );
STATIC_ASSERT( w == 1 );
}
@@ -59,34 +69,34 @@ int main()
#else
{
constexpr auto w = test<variant<Y>, Y>( variant<Y>( 1 ) );
constexpr auto w = test<variant<Y>, 0>( variant<Y>( 1 ) );
STATIC_ASSERT( w == 1 );
}
#endif
{
constexpr auto w = test<variant<int, float>, int>( variant<int, float>( 1 ) );
constexpr auto w = test<variant<int, float>, 0>( variant<int, float>( 1 ) );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<variant<int, float>, float>( variant<int, float>( 3.0f ) );
constexpr auto w = test<variant<int, float>, 1>( variant<int, float>( 3.0f ) );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr auto w = test<variant<int, int, float>, float>( variant<int, int, float>( 3.0f ) );
constexpr auto w = test<variant<int, int, float>, 2>( variant<int, int, float>( 3.0f ) );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr auto w = test<variant<E, E, X>, X>( variant<E, E, X>( 1 ) );
constexpr auto w = test<variant<E, E, X>, 2>( variant<E, E, X>( 1 ) );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<variant<int, int, float, float, X>, X>( variant<int, int, float, float, X>( X(1) ) );
constexpr auto w = test<variant<int, int, float, float, X>, 4>( variant<int, int, float, float, X>( X(1) ) );
STATIC_ASSERT( w == 1 );
}
@@ -94,14 +104,16 @@ int main()
#else
{
constexpr auto w = test<variant<E, E, Y>, Y>( variant<E, E, Y>( 1 ) );
constexpr auto w = test<variant<E, E, Y>, 2>( variant<E, E, Y>( 1 ) );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<variant<int, int, float, float, Y>, Y>( variant<int, int, float, float, Y>( Y(1) ) );
constexpr auto w = test<variant<int, int, float, float, Y>, 4>( variant<int, int, float, float, Y>( Y(1) ) );
STATIC_ASSERT( w == 1 );
}
#endif
}
#endif

View File

@@ -45,7 +45,7 @@ void test()
variant<Y1, Y2> v1( in_place_type_t<Y1>{} );
variant<Y1, Y2> v2( in_place_type_t<Y2>{} );
BOOST_TEST_THROWS( v1 = std::move( v2 ), std::runtime_error )
BOOST_TEST_THROWS( v1 = std::move( v2 ), std::runtime_error );
}
int main()

View File

@@ -1,14 +1,19 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#include <utility>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
using namespace boost::variant2;
struct X
@@ -34,21 +39,21 @@ enum E
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
template<class T, class V> constexpr T test( V&& v )
template<std::size_t I, class V> constexpr variant_alternative_t<I, V> test( V&& v )
{
V v2( std::forward<V>(v) );
return get<T>( v2 );
return get<I>( v2 );
}
int main()
{
{
constexpr auto w = test<int>( variant<int>( 1 ) );
constexpr auto w = test<0>( variant<int>( 1 ) );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<X>( variant<X>( 1 ) );
constexpr auto w = test<0>( variant<X>( 1 ) );
STATIC_ASSERT( w == 1 );
}
@@ -56,34 +61,34 @@ int main()
#else
{
constexpr auto w = test<Y>( variant<Y>( 1 ) );
constexpr auto w = test<0>( variant<Y>( 1 ) );
STATIC_ASSERT( w == 1 );
}
#endif
{
constexpr auto w = test<int>( variant<int, float>( 1 ) );
constexpr auto w = test<0>( variant<int, float>( 1 ) );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<float>( variant<int, float>( 3.0f ) );
constexpr auto w = test<1>( variant<int, float>( 3.0f ) );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr auto w = test<float>( variant<int, int, float>( 3.0f ) );
constexpr auto w = test<2>( variant<int, int, float>( 3.0f ) );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr auto w = test<X>( variant<E, E, X>( 1 ) );
constexpr auto w = test<2>( variant<E, E, X>( 1 ) );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<X>( variant<int, int, float, float, X>( X(1) ) );
constexpr auto w = test<4>( variant<int, int, float, float, X>( X(1) ) );
STATIC_ASSERT( w == 1 );
}
@@ -91,14 +96,16 @@ int main()
#else
{
constexpr auto w = test<Y>( variant<E, E, Y>( 1 ) );
constexpr auto w = test<2>( variant<E, E, Y>( 1 ) );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<Y>( variant<int, int, float, float, Y>( Y(1) ) );
constexpr auto w = test<4>( variant<int, int, float, float, Y>( Y(1) ) );
STATIC_ASSERT( w == 1 );
}
#endif
}
#endif

View File

@@ -1,12 +1,17 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
using namespace boost::variant2;
@@ -33,24 +38,24 @@ enum E
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
template<class V, class T, class A> constexpr A test( A const& a )
template<class V, std::size_t I, class A> constexpr variant_alternative_t<I, V> test( A const& a )
{
V v;
v = a;
return get<T>(v);
return get<I>(v);
}
int main()
{
{
constexpr auto w = test<variant<int>, int>( 1 );
constexpr auto w = test<variant<int>, 0>( 1 );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<variant<X>, X>( 1 );
constexpr auto w = test<variant<X>, 0>( 1 );
STATIC_ASSERT( w == 1 );
}
@@ -58,34 +63,34 @@ int main()
#else
{
constexpr auto w = test<variant<Y>, Y>( 1 );
constexpr auto w = test<variant<Y>, 0>( 1 );
STATIC_ASSERT( w == 1 );
}
#endif
{
constexpr auto w = test<variant<int, float>, int>( 1 );
constexpr auto w = test<variant<int, float>, 0>( 1 );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<variant<int, float>, float>( 3.0f );
constexpr auto w = test<variant<int, float>, 1>( 3.0f );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr auto w = test<variant<int, int, float>, float>( 3.0f );
constexpr auto w = test<variant<int, int, float>, 2>( 3.0f );
STATIC_ASSERT( w == 3.0f );
}
{
constexpr auto w = test<variant<E, E, X>, X>( 1 );
constexpr auto w = test<variant<E, E, X>, 2>( 1 );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<variant<int, int, float, float, X>, X>( X(1) );
constexpr auto w = test<variant<int, int, float, float, X>, 4>( X(1) );
STATIC_ASSERT( w == 1 );
}
@@ -93,14 +98,16 @@ int main()
#else
{
constexpr auto w = test<variant<E, E, Y>, Y>( 1 );
constexpr auto w = test<variant<E, E, Y>, 2>( 1 );
STATIC_ASSERT( w == 1 );
}
{
constexpr auto w = test<variant<int, int, float, float, Y>, Y>( Y(1) );
constexpr auto w = test<variant<int, int, float, float, Y>, 4>( Y(1) );
STATIC_ASSERT( w == 1 );
}
#endif
}
#endif

View File

@@ -1,12 +1,17 @@
// Copyright 2017 Peter Dimov.
//
// Copyright 2017, 2026 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
#include <boost/variant2/variant.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_MSVC) && BOOST_MSVC < 1910
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC < 1910" )
int main() {}
#else
using namespace boost::variant2;
@@ -107,3 +112,5 @@ int main()
STATIC_ASSERT( holds_alternative<X>(v) );
}
}
#endif

View File

@@ -0,0 +1,32 @@
// Copyright 2025 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/config/pragma_message.hpp>
#if !defined(__cpp_constexpr_dynamic_alloc) || __cpp_constexpr_dynamic_alloc < 201907L
BOOST_PRAGMA_MESSAGE("Skipping test because __cpp_constexpr_dynamic_alloc < 201907L")
int main() {}
#else
using namespace boost::variant2;
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
struct X
{
constexpr ~X() {}
};
int main()
{
constexpr variant<X, int> v( 5 );
STATIC_ASSERT( v.index() == 1 );
STATIC_ASSERT( get<1>(v) == 5 );
}
#endif

View File

@@ -0,0 +1,37 @@
// Copyright 2025 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/config/pragma_message.hpp>
#if !defined(__cpp_constexpr_dynamic_alloc) || __cpp_constexpr_dynamic_alloc < 201907L
BOOST_PRAGMA_MESSAGE("Skipping test because __cpp_constexpr_dynamic_alloc < 201907L")
int main() {}
#elif defined(BOOST_CLANG) && BOOST_CLANG_VERSION < 180000
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_CLANG_VERSION < 180000")
int main() {}
#else
using namespace boost::variant2;
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
struct X
{
~X() {}
};
int main()
{
constexpr variant<X, int> v( 5 );
STATIC_ASSERT( v.index() == 1 );
STATIC_ASSERT( get<1>(v) == 5 );
}
#endif

View File

@@ -0,0 +1,56 @@
// Copyright 2025 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/config/pragma_message.hpp>
#if !defined(__cpp_constexpr_dynamic_alloc) || __cpp_constexpr_dynamic_alloc < 201907L
BOOST_PRAGMA_MESSAGE("Skipping test because __cpp_constexpr_dynamic_alloc < 201907L")
int main() {}
#elif defined(BOOST_MSVC) && BOOST_MSVC < 1960
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_MSVC < 1960")
int main() {}
#elif defined(BOOST_CLANG) && BOOST_CLANG_VERSION < 180000
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_CLANG_VERSION < 180000")
int main() {}
#else
using namespace boost::variant2;
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
struct X
{
};
struct Y
{
constexpr ~Y() {}
};
struct Z
{
~Z() {}
};
int main()
{
{
constexpr variant<X, Y, Z> v( X{} );
STATIC_ASSERT( v.index() == 0 );
}
{
constexpr variant<X, Y, Z> v( Y{} );
STATIC_ASSERT( v.index() == 1 );
}
}
#endif

View File

@@ -1,20 +1,26 @@
// Copyright 2017, 2024 Peter Dimov
// Copyright 2017, 2024, 2026 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
using namespace boost::variant2;
#if !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR)
#include <boost/mp11.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping constexpr visit test because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined")
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#elif !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE("Skipping constexpr visit test because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined")
int main() {}
#else
using namespace boost::variant2;
struct X
{
constexpr operator int() const { return 2; }

View File

@@ -1,20 +1,26 @@
// Copyright 2017, 2024 Peter Dimov
// Copyright 2017, 2024, 2026 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/variant2/variant.hpp>
using namespace boost::variant2;
#if !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR)
#include <boost/mp11.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping constexpr visit test because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined")
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#elif !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE("Skipping constexpr visit test because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined")
int main() {}
#else
using namespace boost::variant2;
struct X
{
int v;