mirror of
https://github.com/boostorg/variant2.git
synced 2025-12-24 07:38:06 +01:00
Compare commits
31 Commits
feature/ad
...
feature/vi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
772ef0d312 | ||
|
|
f3b3b533aa | ||
|
|
4b60dee4b6 | ||
|
|
76c67c9b21 | ||
|
|
308bd731a5 | ||
|
|
719c43316f | ||
|
|
d6680df4e5 | ||
|
|
8cf72527a6 | ||
|
|
b649a39776 | ||
|
|
37f6efab5d | ||
|
|
5259bdd5fc | ||
|
|
9964e77dd2 | ||
|
|
57ab36bd95 | ||
|
|
fac5992e45 | ||
|
|
972280e59f | ||
|
|
ef2ef292b9 | ||
|
|
3b2fb1a48a | ||
|
|
4f81882bfd | ||
|
|
17bc06b090 | ||
|
|
c4cad3e96a | ||
|
|
83ff667813 | ||
|
|
5e76451843 | ||
|
|
c2b5d101eb | ||
|
|
a92185a86d | ||
|
|
a795f9cf01 | ||
|
|
f6e2e78d7d | ||
|
|
1f05cdfb17 | ||
|
|
1203aa97c0 | ||
|
|
b3229d48b7 | ||
|
|
be11d94adc | ||
|
|
fece11142c |
20
.travis.yml
20
.travis.yml
@@ -4,8 +4,6 @@
|
||||
|
||||
language: cpp
|
||||
|
||||
sudo: false
|
||||
|
||||
dist: xenial
|
||||
|
||||
branches:
|
||||
@@ -25,8 +23,14 @@ matrix:
|
||||
|
||||
include:
|
||||
- os: linux
|
||||
compiler: g++
|
||||
env: TOOLSET=gcc COMPILER=g++ CXXSTD=11
|
||||
compiler: g++-4.8
|
||||
env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD=11
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-4.8
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-4.9
|
||||
@@ -98,6 +102,11 @@ matrix:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
dist: trusty
|
||||
compiler: clang++
|
||||
env: DIST=trusty TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-3.5
|
||||
env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=11,14,1z
|
||||
@@ -259,7 +268,6 @@ matrix:
|
||||
- ctest --output-on-failure -R boost_variant2
|
||||
|
||||
- os: linux
|
||||
compiler: g++
|
||||
env: CMAKE_SUBDIR_TEST=1
|
||||
install:
|
||||
- BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
@@ -277,7 +285,7 @@ matrix:
|
||||
env: CMAKE_INSTALL_TEST=1
|
||||
script:
|
||||
- mkdir __build__ && cd __build__
|
||||
- cmake -DBOOST_ENABLE_CMAKE=1 -DBoost_VERBOSE=1 -DBOOST_INCLUDE_LIBRARIES="variant2;config;mp11" -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
- cmake -DBOOST_ENABLE_CMAKE=1 -DBoost_VERBOSE=1 -DBOOST_INCLUDE_LIBRARIES=variant2 -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
- cmake --build . --target install
|
||||
- cd ../libs/variant2/test/cmake_install_test && mkdir __build__ && cd __build__
|
||||
- cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
|
||||
14
appveyor.yml
14
appveyor.yml
@@ -1,4 +1,4 @@
|
||||
# Copyright 2016-2018 Peter Dimov
|
||||
# Copyright 2016-2020 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -21,6 +21,14 @@ environment:
|
||||
TOOLSET: msvc-14.1
|
||||
ADDRMD: 32,64
|
||||
CXXSTD: 14,17
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: clang-win
|
||||
ADDRMD: 64
|
||||
CXXSTD: 14,17
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
TOOLSET: msvc-14.2
|
||||
ADDRMD: 32,64
|
||||
CXXSTD: 14,17
|
||||
|
||||
install:
|
||||
- set BOOST_BRANCH=develop
|
||||
@@ -28,8 +36,6 @@ install:
|
||||
- cd ..
|
||||
- git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
- cd boost-root
|
||||
- git submodule update --init tools/build
|
||||
- git submodule update --init libs/config
|
||||
- git submodule update --init tools/boostdep
|
||||
- xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\variant2\
|
||||
- python tools/boostdep/depinst/depinst.py variant2
|
||||
@@ -41,4 +47,4 @@ build: off
|
||||
test_script:
|
||||
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
|
||||
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
|
||||
- b2 libs/variant2/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release
|
||||
- b2 -j3 libs/variant2/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
////
|
||||
Copyright 2019 Peter Dimov
|
||||
Copyright 2019, 2020 Peter Dimov
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
|
||||
@@ -11,6 +11,13 @@ http://www.boost.org/LICENSE_1_0.txt
|
||||
# Revision History
|
||||
:idprefix: changelog_
|
||||
|
||||
## Changes in 1.73.0
|
||||
|
||||
* Added support for `std::hash`, `boost::hash`.
|
||||
* `variant<T...>` is now trivial when all types in `T...` are trivial.
|
||||
This improves performance by enabling it to be passed to, and returned
|
||||
from, functions in registers.
|
||||
|
||||
## Changes in 1.71.0
|
||||
|
||||
After the Boost formal review, the implementation has been
|
||||
|
||||
@@ -169,8 +169,6 @@ The main differences between this implementation and `std::variant` are:
|
||||
`variant<int, float>` is provided as the member function `subset<U...>`.
|
||||
(This operation can throw if the current state of the variant cannot be
|
||||
represented.)
|
||||
* `variant<T...>` is not (yet) trivial when all contained types are trivial,
|
||||
as mandated by {cpp}17.
|
||||
* The {cpp}20 additions and changes to `std::variant` have not yet been
|
||||
implemented.
|
||||
|
||||
|
||||
@@ -18,12 +18,14 @@
|
||||
#endif
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <exception>
|
||||
#include <cassert>
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
#include <functional> // std::hash
|
||||
|
||||
//
|
||||
|
||||
@@ -1050,20 +1052,317 @@ template<class T> struct is_nothrow_swappable: mp11::mp_valid<det2::is_nothrow_s
|
||||
|
||||
#endif
|
||||
|
||||
// variant_cc_base
|
||||
|
||||
template<bool CopyConstructible, bool TriviallyCopyConstructible, class... T> struct variant_cc_base_impl;
|
||||
|
||||
template<class... T> using variant_cc_base = variant_cc_base_impl<
|
||||
mp11::mp_all<std::is_copy_constructible<T>...>::value,
|
||||
mp11::mp_all<detail::is_trivially_copy_constructible<T>...>::value,
|
||||
T...>;
|
||||
|
||||
template<class... T> struct variant_cc_base_impl<true, true, T...>: public variant_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
variant_cc_base_impl() = default;
|
||||
variant_cc_base_impl( variant_cc_base_impl const& ) = default;
|
||||
variant_cc_base_impl( variant_cc_base_impl && ) = default;
|
||||
variant_cc_base_impl& operator=( variant_cc_base_impl const& ) = default;
|
||||
variant_cc_base_impl& operator=( variant_cc_base_impl && ) = default;
|
||||
};
|
||||
|
||||
template<bool B, class... T> struct variant_cc_base_impl<false, B, T...>: public variant_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
variant_cc_base_impl() = default;
|
||||
variant_cc_base_impl( variant_cc_base_impl const& ) = delete;
|
||||
variant_cc_base_impl( variant_cc_base_impl && ) = default;
|
||||
variant_cc_base_impl& operator=( variant_cc_base_impl const& ) = default;
|
||||
variant_cc_base_impl& operator=( variant_cc_base_impl && ) = default;
|
||||
};
|
||||
|
||||
template<class... T> struct variant_cc_base_impl<true, false, T...>: public variant_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
public:
|
||||
|
||||
// constructors
|
||||
|
||||
variant_cc_base_impl() = default;
|
||||
|
||||
// copy constructor
|
||||
|
||||
private:
|
||||
|
||||
struct L1
|
||||
{
|
||||
variant_base * this_;
|
||||
variant_base const & r;
|
||||
|
||||
template<class I> void operator()( I i ) const
|
||||
{
|
||||
this_->_replace( i, r._get_impl( i ) );
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
variant_cc_base_impl( variant_cc_base_impl const& r )
|
||||
noexcept( mp11::mp_all<std::is_nothrow_copy_constructible<T>...>::value )
|
||||
: variant_base()
|
||||
{
|
||||
mp11::mp_with_index<sizeof...(T)>( r.index(), L1{ this, r } );
|
||||
}
|
||||
|
||||
// move constructor
|
||||
|
||||
variant_cc_base_impl( variant_cc_base_impl && ) = default;
|
||||
|
||||
// assignment
|
||||
|
||||
variant_cc_base_impl& operator=( variant_cc_base_impl const & ) = default;
|
||||
variant_cc_base_impl& operator=( variant_cc_base_impl && ) = default;
|
||||
};
|
||||
|
||||
// variant_ca_base
|
||||
|
||||
template<bool CopyAssignable, bool TriviallyCopyAssignable, class... T> struct variant_ca_base_impl;
|
||||
|
||||
template<class... T> using variant_ca_base = variant_ca_base_impl<
|
||||
mp11::mp_all<std::is_copy_constructible<T>..., std::is_copy_assignable<T>...>::value,
|
||||
mp11::mp_all<std::is_trivially_destructible<T>..., detail::is_trivially_copy_constructible<T>..., detail::is_trivially_copy_assignable<T>...>::value,
|
||||
T...>;
|
||||
|
||||
template<class... T> struct variant_ca_base_impl<true, true, T...>: public variant_cc_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_cc_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
variant_ca_base_impl() = default;
|
||||
variant_ca_base_impl( variant_ca_base_impl const& ) = default;
|
||||
variant_ca_base_impl( variant_ca_base_impl && ) = default;
|
||||
variant_ca_base_impl& operator=( variant_ca_base_impl const& ) = default;
|
||||
variant_ca_base_impl& operator=( variant_ca_base_impl && ) = default;
|
||||
};
|
||||
|
||||
template<bool B, class... T> struct variant_ca_base_impl<false, B, T...>: public variant_cc_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_cc_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
variant_ca_base_impl() = default;
|
||||
variant_ca_base_impl( variant_ca_base_impl const& ) = default;
|
||||
variant_ca_base_impl( variant_ca_base_impl && ) = default;
|
||||
variant_ca_base_impl& operator=( variant_ca_base_impl const& ) = delete;
|
||||
variant_ca_base_impl& operator=( variant_ca_base_impl && ) = default;
|
||||
};
|
||||
|
||||
template<class... T> struct variant_ca_base_impl<true, false, T...>: public variant_cc_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_cc_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
public:
|
||||
|
||||
// constructors
|
||||
|
||||
variant_ca_base_impl() = default;
|
||||
variant_ca_base_impl( variant_ca_base_impl const& ) = default;
|
||||
variant_ca_base_impl( variant_ca_base_impl && ) = default;
|
||||
|
||||
// copy assignment
|
||||
|
||||
private:
|
||||
|
||||
struct L3
|
||||
{
|
||||
variant_base * this_;
|
||||
variant_base const & r;
|
||||
|
||||
template<class I> void operator()( I i ) const
|
||||
{
|
||||
this_->template emplace<I::value>( r._get_impl( i ) );
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
BOOST_CXX14_CONSTEXPR variant_ca_base_impl& operator=( variant_ca_base_impl const & r )
|
||||
noexcept( mp11::mp_all<std::is_nothrow_copy_constructible<T>...>::value )
|
||||
{
|
||||
mp11::mp_with_index<sizeof...(T)>( r.index(), L3{ this, r } );
|
||||
return *this;
|
||||
}
|
||||
|
||||
// move assignment
|
||||
|
||||
variant_ca_base_impl& operator=( variant_ca_base_impl && ) = default;
|
||||
};
|
||||
|
||||
// variant_mc_base
|
||||
|
||||
template<bool MoveConstructible, bool TriviallyMoveConstructible, class... T> struct variant_mc_base_impl;
|
||||
|
||||
template<class... T> using variant_mc_base = variant_mc_base_impl<
|
||||
mp11::mp_all<std::is_move_constructible<T>...>::value,
|
||||
mp11::mp_all<detail::is_trivially_move_constructible<T>...>::value,
|
||||
T...>;
|
||||
|
||||
template<class... T> struct variant_mc_base_impl<true, true, T...>: public variant_ca_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_ca_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
variant_mc_base_impl() = default;
|
||||
variant_mc_base_impl( variant_mc_base_impl const& ) = default;
|
||||
variant_mc_base_impl( variant_mc_base_impl && ) = default;
|
||||
variant_mc_base_impl& operator=( variant_mc_base_impl const& ) = default;
|
||||
variant_mc_base_impl& operator=( variant_mc_base_impl && ) = default;
|
||||
};
|
||||
|
||||
template<bool B, class... T> struct variant_mc_base_impl<false, B, T...>: public variant_ca_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_ca_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
variant_mc_base_impl() = default;
|
||||
variant_mc_base_impl( variant_mc_base_impl const& ) = default;
|
||||
variant_mc_base_impl( variant_mc_base_impl && ) = delete;
|
||||
variant_mc_base_impl& operator=( variant_mc_base_impl const& ) = default;
|
||||
variant_mc_base_impl& operator=( variant_mc_base_impl && ) = default;
|
||||
};
|
||||
|
||||
template<class... T> struct variant_mc_base_impl<true, false, T...>: public variant_ca_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_ca_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
public:
|
||||
|
||||
// constructors
|
||||
|
||||
variant_mc_base_impl() = default;
|
||||
variant_mc_base_impl( variant_mc_base_impl const& ) = default;
|
||||
|
||||
// move constructor
|
||||
|
||||
private:
|
||||
|
||||
struct L2
|
||||
{
|
||||
variant_base * this_;
|
||||
variant_base & r;
|
||||
|
||||
template<class I> void operator()( I i ) const
|
||||
{
|
||||
this_->_replace( i, std::move( r._get_impl( i ) ) );
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
variant_mc_base_impl( variant_mc_base_impl && r )
|
||||
noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value )
|
||||
{
|
||||
mp11::mp_with_index<sizeof...(T)>( r.index(), L2{ this, r } );
|
||||
}
|
||||
|
||||
// assignment
|
||||
|
||||
variant_mc_base_impl& operator=( variant_mc_base_impl const & ) = default;
|
||||
variant_mc_base_impl& operator=( variant_mc_base_impl && ) = default;
|
||||
};
|
||||
|
||||
// variant_ma_base
|
||||
|
||||
template<bool MoveAssignable, bool TriviallyMoveAssignable, class... T> struct variant_ma_base_impl;
|
||||
|
||||
template<class... T> using variant_ma_base = variant_ma_base_impl<
|
||||
mp11::mp_all<std::is_move_constructible<T>..., std::is_move_assignable<T>...>::value,
|
||||
mp11::mp_all<std::is_trivially_destructible<T>..., detail::is_trivially_move_constructible<T>..., detail::is_trivially_move_assignable<T>...>::value,
|
||||
T...>;
|
||||
|
||||
template<class... T> struct variant_ma_base_impl<true, true, T...>: public variant_mc_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_mc_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
variant_ma_base_impl() = default;
|
||||
variant_ma_base_impl( variant_ma_base_impl const& ) = default;
|
||||
variant_ma_base_impl( variant_ma_base_impl && ) = default;
|
||||
variant_ma_base_impl& operator=( variant_ma_base_impl const& ) = default;
|
||||
variant_ma_base_impl& operator=( variant_ma_base_impl && ) = default;
|
||||
};
|
||||
|
||||
template<bool B, class... T> struct variant_ma_base_impl<false, B, T...>: public variant_mc_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_mc_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
variant_ma_base_impl() = default;
|
||||
variant_ma_base_impl( variant_ma_base_impl const& ) = default;
|
||||
variant_ma_base_impl( variant_ma_base_impl && ) = default;
|
||||
variant_ma_base_impl& operator=( variant_ma_base_impl const& ) = default;
|
||||
variant_ma_base_impl& operator=( variant_ma_base_impl && ) = delete;
|
||||
};
|
||||
|
||||
template<class... T> struct variant_ma_base_impl<true, false, T...>: public variant_mc_base<T...>
|
||||
{
|
||||
using variant_base = detail::variant_mc_base<T...>;
|
||||
using variant_base::variant_base;
|
||||
|
||||
public:
|
||||
|
||||
// constructors
|
||||
|
||||
variant_ma_base_impl() = default;
|
||||
variant_ma_base_impl( variant_ma_base_impl const& ) = default;
|
||||
variant_ma_base_impl( variant_ma_base_impl && ) = default;
|
||||
|
||||
// copy assignment
|
||||
|
||||
variant_ma_base_impl& operator=( variant_ma_base_impl const & ) = default;
|
||||
|
||||
// move assignment
|
||||
|
||||
private:
|
||||
|
||||
struct L4
|
||||
{
|
||||
variant_base * this_;
|
||||
variant_base & r;
|
||||
|
||||
template<class I> void operator()( I i ) const
|
||||
{
|
||||
this_->template emplace<I::value>( std::move( r._get_impl( i ) ) );
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
variant_ma_base_impl& operator=( variant_ma_base_impl && r )
|
||||
noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value )
|
||||
{
|
||||
mp11::mp_with_index<sizeof...(T)>( r.index(), L4{ this, r } );
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// variant
|
||||
|
||||
template<class... T> class variant: private detail::variant_base<T...>
|
||||
template<class... T> class variant: private detail::variant_ma_base<T...>
|
||||
{
|
||||
private:
|
||||
|
||||
using variant_base = detail::variant_base<T...>;
|
||||
|
||||
private:
|
||||
|
||||
variant( variant const volatile& r ) = delete;
|
||||
variant& operator=( variant const volatile& r ) = delete;
|
||||
using variant_base = detail::variant_ma_base<T...>;
|
||||
|
||||
public:
|
||||
|
||||
@@ -1076,71 +1375,8 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
template<class E1 = void,
|
||||
class E2 = mp11::mp_if<mp11::mp_all<detail::is_trivially_copy_constructible<T>...>, E1>
|
||||
>
|
||||
constexpr variant( variant const& r ) noexcept
|
||||
: variant_base( static_cast<variant_base const&>(r) )
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct L1
|
||||
{
|
||||
variant_base * this_;
|
||||
variant const & r;
|
||||
|
||||
template<class I> void operator()( I i ) const
|
||||
{
|
||||
this_->_replace( i, r._get_impl( i ) );
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
template<class E1 = void,
|
||||
class E2 = mp11::mp_if<mp11::mp_not<mp11::mp_all<detail::is_trivially_copy_constructible<T>...>>, E1>,
|
||||
class E3 = mp11::mp_if<mp11::mp_all<std::is_copy_constructible<T>...>, E1>
|
||||
>
|
||||
variant( variant const& r )
|
||||
noexcept( mp11::mp_all<std::is_nothrow_copy_constructible<T>...>::value )
|
||||
{
|
||||
mp11::mp_with_index<sizeof...(T)>( r.index(), L1{ this, r } );
|
||||
}
|
||||
|
||||
template<class E1 = void,
|
||||
class E2 = mp11::mp_if<mp11::mp_all<detail::is_trivially_move_constructible<T>...>, E1>
|
||||
>
|
||||
constexpr variant( variant && r ) noexcept
|
||||
: variant_base( static_cast<variant_base&&>(r) )
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct L2
|
||||
{
|
||||
variant_base * this_;
|
||||
variant & r;
|
||||
|
||||
template<class I> void operator()( I i ) const
|
||||
{
|
||||
this_->_replace( i, std::move( r._get_impl( i ) ) );
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
template<class E1 = void,
|
||||
class E2 = mp11::mp_if<mp11::mp_not<mp11::mp_all<detail::is_trivially_move_constructible<T>...>>, E1>,
|
||||
class E3 = mp11::mp_if<mp11::mp_all<std::is_move_constructible<T>...>, E1>
|
||||
>
|
||||
variant( variant && r )
|
||||
noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value )
|
||||
{
|
||||
mp11::mp_with_index<sizeof...(T)>( r.index(), L2{ this, r } );
|
||||
}
|
||||
// variant( variant const& ) = default;
|
||||
// variant( variant && ) = default;
|
||||
|
||||
template<class U,
|
||||
class Ud = typename std::decay<U>::type,
|
||||
@@ -1175,75 +1411,9 @@ public:
|
||||
}
|
||||
|
||||
// assignment
|
||||
template<class E1 = void,
|
||||
class E2 = mp11::mp_if<mp11::mp_all<std::is_trivially_destructible<T>..., detail::is_trivially_copy_constructible<T>..., detail::is_trivially_copy_assignable<T>...>, E1>
|
||||
>
|
||||
BOOST_CXX14_CONSTEXPR variant& operator=( variant const & r ) noexcept
|
||||
{
|
||||
static_cast<variant_base&>( *this ) = static_cast<variant_base const&>( r );
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct L3
|
||||
{
|
||||
variant * this_;
|
||||
variant const & r;
|
||||
|
||||
template<class I> void operator()( I i ) const
|
||||
{
|
||||
this_->variant_base::template emplace<I::value>( r._get_impl( i ) );
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
template<class E1 = void,
|
||||
class E2 = mp11::mp_if<mp11::mp_not<mp11::mp_all<std::is_trivially_destructible<T>..., detail::is_trivially_copy_constructible<T>..., detail::is_trivially_copy_assignable<T>...>>, E1>,
|
||||
class E3 = mp11::mp_if<mp11::mp_all<std::is_copy_constructible<T>..., std::is_copy_assignable<T>...>, E1>
|
||||
>
|
||||
BOOST_CXX14_CONSTEXPR variant& operator=( variant const & r )
|
||||
noexcept( mp11::mp_all<std::is_nothrow_copy_constructible<T>...>::value )
|
||||
{
|
||||
mp11::mp_with_index<sizeof...(T)>( r.index(), L3{ this, r } );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class E1 = void,
|
||||
class E2 = mp11::mp_if<mp11::mp_all<std::is_trivially_destructible<T>..., detail::is_trivially_move_constructible<T>..., detail::is_trivially_move_assignable<T>...>, E1>
|
||||
>
|
||||
BOOST_CXX14_CONSTEXPR variant& operator=( variant && r ) noexcept
|
||||
{
|
||||
static_cast<variant_base&>( *this ) = static_cast<variant_base&&>( r );
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct L4
|
||||
{
|
||||
variant * this_;
|
||||
variant & r;
|
||||
|
||||
template<class I> void operator()( I i ) const
|
||||
{
|
||||
this_->variant_base::template emplace<I::value>( std::move( r._get_impl( i ) ) );
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
template<class E1 = void,
|
||||
class E2 = mp11::mp_if<mp11::mp_not<mp11::mp_all<std::is_trivially_destructible<T>..., detail::is_trivially_move_constructible<T>..., detail::is_trivially_move_assignable<T>...>>, E1>,
|
||||
class E3 = mp11::mp_if<mp11::mp_all<std::is_move_constructible<T>..., std::is_move_assignable<T>...>, E1>
|
||||
>
|
||||
variant& operator=( variant && r )
|
||||
noexcept( mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value )
|
||||
{
|
||||
mp11::mp_with_index<sizeof...(T)>( r.index(), L4{ this, r } );
|
||||
return *this;
|
||||
}
|
||||
// variant& operator=( variant const& ) = default;
|
||||
// variant& operator=( variant && ) = default;
|
||||
|
||||
template<class U,
|
||||
class E1 = typename std::enable_if<!std::is_same<typename std::decay<U>::type, variant>::value>::type,
|
||||
@@ -1598,6 +1768,25 @@ namespace detail
|
||||
|
||||
template<class T> using remove_cv_ref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
|
||||
template<class... T> variant<T...> const & extract_variant_base_( variant<T...> const & );
|
||||
|
||||
#if BOOST_WORKAROUND( BOOST_MSVC, < 1930 )
|
||||
|
||||
template<class V> struct extract_vbase_impl
|
||||
{
|
||||
using type = decltype( extract_variant_base_( std::declval<V>() ) );
|
||||
};
|
||||
|
||||
template<class V> using extract_variant_base = remove_cv_ref_t< typename extract_vbase_impl<V>::type >;
|
||||
|
||||
#else
|
||||
|
||||
template<class V> using extract_variant_base = remove_cv_ref_t< decltype( extract_variant_base_( std::declval<V>() ) ) >;
|
||||
|
||||
#endif
|
||||
|
||||
template<class V> using variant_base_size = variant_size< extract_variant_base<V> >;
|
||||
|
||||
template<class T, class U> struct copy_cv_ref
|
||||
{
|
||||
using type = T;
|
||||
@@ -1637,7 +1826,7 @@ template<class F> struct Qret
|
||||
|
||||
template<class L> using front_if_same = mp11::mp_if<mp11::mp_apply<mp11::mp_same, L>, mp11::mp_front<L>>;
|
||||
|
||||
template<class V> using apply_cv_ref = mp11::mp_product<copy_cv_ref_t, remove_cv_ref_t<V>, mp11::mp_list<V>>;
|
||||
template<class V> using apply_cv_ref = mp11::mp_product<copy_cv_ref_t, extract_variant_base<V>, mp11::mp_list<V>>;
|
||||
|
||||
template<class F, class... V> using Vret = front_if_same<mp11::mp_product_q<Qret<F>, apply_cv_ref<V>...>>;
|
||||
|
||||
@@ -1666,7 +1855,7 @@ template<class F, class V1> struct visit_L1
|
||||
|
||||
template<class F, class V1> constexpr auto visit( F&& f, V1&& v1 ) -> detail::Vret<F, V1>
|
||||
{
|
||||
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L1<F, V1>{ std::forward<F>(f), std::forward<V1>(v1) } );
|
||||
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L1<F, V1>{ std::forward<F>(f), std::forward<V1>(v1) } );
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) || BOOST_WORKAROUND( BOOST_MSVC, < 1920 )
|
||||
@@ -1708,7 +1897,7 @@ template<class F, class V1, class V2> struct visit_L2
|
||||
|
||||
template<class F, class V1, class V2> constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> detail::Vret<F, V1, V2>
|
||||
{
|
||||
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L2<F, V1, V2>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2) } );
|
||||
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L2<F, V1, V2>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2) } );
|
||||
}
|
||||
|
||||
namespace detail
|
||||
@@ -1733,7 +1922,7 @@ template<class F, class V1, class V2, class V3> struct visit_L3
|
||||
|
||||
template<class F, class V1, class V2, class V3> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> detail::Vret<F, V1, V2, V3>
|
||||
{
|
||||
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L3<F, V1, V2, V3>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3) } );
|
||||
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L3<F, V1, V2, V3>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3) } );
|
||||
}
|
||||
|
||||
namespace detail
|
||||
@@ -1759,14 +1948,14 @@ template<class F, class V1, class V2, class V3, class V4> struct visit_L4
|
||||
|
||||
template<class F, class V1, class V2, class V3, class V4> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3, V4&& v4 ) -> detail::Vret<F, V1, V2, V3, V4>
|
||||
{
|
||||
return mp11::mp_with_index<variant_size<V1>>( v1.index(), detail::visit_L4<F, V1, V2, V3, V4>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) } );
|
||||
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), detail::visit_L4<F, V1, V2, V3, V4>{ std::forward<F>(f), std::forward<V1>(v1), std::forward<V2>(v2), std::forward<V3>(v3), std::forward<V4>(v4) } );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<class F, class V1, class V2, class... V> constexpr auto visit( F&& f, V1&& v1, V2&& v2, V&&... v ) -> detail::Vret<F, V1, V2, V...>
|
||||
{
|
||||
return mp11::mp_with_index<variant_size<V1>>( v1.index(), [&]( auto I ){
|
||||
return mp11::mp_with_index<detail::variant_base_size<V1>>( v1.index(), [&]( auto I ){
|
||||
|
||||
auto f2 = [&]( auto&&... a ){ return std::forward<F>(f)( detail::unsafe_get<I.value>( std::forward<V1>(v1) ), std::forward<decltype(a)>(a)... ); };
|
||||
return visit( f2, std::forward<V2>(v2), std::forward<V>(v)... );
|
||||
@@ -1785,9 +1974,92 @@ void swap( variant<T...> & v, variant<T...> & w )
|
||||
v.swap( w );
|
||||
}
|
||||
|
||||
// hashing support
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class V> struct hash_value_L
|
||||
{
|
||||
V const & v;
|
||||
|
||||
template<class I> std::size_t operator()( I ) const
|
||||
{
|
||||
boost::ulong_long_type hv = ( boost::ulong_long_type( 0xCBF29CE4 ) << 32 ) + 0x84222325;
|
||||
boost::ulong_long_type const prime = ( boost::ulong_long_type( 0x00000100 ) << 32 ) + 0x000001B3;
|
||||
|
||||
// index
|
||||
|
||||
hv ^= I::value;
|
||||
hv *= prime;
|
||||
|
||||
// value
|
||||
|
||||
auto const & t = unsafe_get<I::value>( v );
|
||||
|
||||
hv ^= std::hash<remove_cv_ref_t<decltype(t)>>()( t );
|
||||
hv *= prime;
|
||||
|
||||
return static_cast<std::size_t>( hv );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
inline std::size_t hash_value( monostate const & )
|
||||
{
|
||||
return 0xA7EE4757u;
|
||||
}
|
||||
|
||||
template<class... T> std::size_t hash_value( variant<T...> const & v )
|
||||
{
|
||||
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::hash_value_L< variant<T...> >{ v } );
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class T> using is_hash_enabled = std::is_default_constructible< std::hash<typename std::remove_const<T>::type> >;
|
||||
|
||||
template<class V, bool E = mp11::mp_all_of<V, is_hash_enabled>::value> struct std_hash_impl;
|
||||
|
||||
template<class V> struct std_hash_impl<V, false>
|
||||
{
|
||||
std_hash_impl() = delete;
|
||||
std_hash_impl( std_hash_impl const& ) = delete;
|
||||
std_hash_impl& operator=( std_hash_impl const& ) = delete;
|
||||
};
|
||||
|
||||
template<class V> struct std_hash_impl<V, true>
|
||||
{
|
||||
std::size_t operator()( V const & v ) const
|
||||
{
|
||||
return hash_value( v );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace variant2
|
||||
} // namespace boost
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<class... T> struct hash< ::boost::variant2::variant<T...> >: public ::boost::variant2::detail::std_hash_impl< ::boost::variant2::variant<T...> >
|
||||
{
|
||||
};
|
||||
|
||||
template<> struct hash< ::boost::variant2::monostate >
|
||||
{
|
||||
std::size_t operator()( ::boost::variant2::monostate const & v ) const
|
||||
{
|
||||
return hash_value( v );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1910
|
||||
# pragma warning( pop )
|
||||
#endif
|
||||
|
||||
@@ -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_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::variant2 Boost::core Boost::container_hash)
|
||||
|
||||
endif()
|
||||
|
||||
27
test/Jamfile
27
test/Jamfile
@@ -12,7 +12,7 @@ import ../../config/checks/config : requires ;
|
||||
project
|
||||
: default-build
|
||||
|
||||
<warnings>all
|
||||
<warnings>extra
|
||||
|
||||
: requirements
|
||||
|
||||
@@ -29,16 +29,16 @@ run variant_size.cpp ;
|
||||
run variant_alternative.cpp ;
|
||||
|
||||
run variant_holds_alternative.cpp ;
|
||||
compile variant_holds_alternative_cx.cpp ;
|
||||
compile variant_holds_alternative_cx.cpp : <toolset>msvc-14.0:<build>no ;
|
||||
|
||||
run variant_get_by_index.cpp ;
|
||||
compile variant_get_by_index_cx.cpp ;
|
||||
compile variant_get_by_index_cx.cpp : <toolset>msvc-14.0:<build>no ;
|
||||
|
||||
run variant_get_by_type.cpp ;
|
||||
compile variant_get_by_type_cx.cpp ;
|
||||
compile variant_get_by_type_cx.cpp : <toolset>msvc-14.0:<build>no ;
|
||||
|
||||
run variant_default_construct.cpp ;
|
||||
compile variant_default_construct_cx.cpp ;
|
||||
compile variant_default_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
|
||||
|
||||
run variant_copy_construct.cpp ;
|
||||
compile variant_copy_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
|
||||
@@ -47,13 +47,13 @@ run variant_move_construct.cpp ;
|
||||
compile variant_move_construct_cx.cpp : [ requires cxx14_constexpr ] ;
|
||||
|
||||
run variant_value_construct.cpp ;
|
||||
compile variant_value_construct_cx.cpp ;
|
||||
compile variant_value_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
|
||||
|
||||
run variant_in_place_index_construct.cpp ;
|
||||
compile variant_in_place_index_construct_cx.cpp ;
|
||||
compile variant_in_place_index_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
|
||||
|
||||
run variant_in_place_type_construct.cpp ;
|
||||
compile variant_in_place_type_construct_cx.cpp ;
|
||||
compile variant_in_place_type_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
|
||||
|
||||
run variant_copy_assign.cpp ;
|
||||
compile variant_copy_assign_cx.cpp : [ requires cxx14_constexpr ] ;
|
||||
@@ -99,9 +99,16 @@ local NX =
|
||||
;
|
||||
|
||||
run variant_get_by_index.cpp throw_exception.cpp : : : $(NX) : variant_get_by_index_nx ;
|
||||
compile variant_get_by_index_cx.cpp : $(NX) : variant_get_by_index_cx_nx ;
|
||||
compile variant_get_by_index_cx.cpp : $(NX) <toolset>msvc-14.0:<build>no : variant_get_by_index_cx_nx ;
|
||||
|
||||
run variant_get_by_type.cpp throw_exception.cpp : : : $(NX) : variant_get_by_type_nx ;
|
||||
compile variant_get_by_type_cx.cpp : $(NX) : variant_get_by_type_cx_nx ;
|
||||
compile variant_get_by_type_cx.cpp : $(NX) <toolset>msvc-14.0:<build>no : variant_get_by_type_cx_nx ;
|
||||
|
||||
run variant_subset.cpp throw_exception.cpp : : : $(NX) : variant_subset_nx ;
|
||||
|
||||
run variant_hash.cpp ;
|
||||
|
||||
run variant_trivial.cpp ;
|
||||
run variant_special.cpp ;
|
||||
|
||||
run variant_visit_derived.cpp ;
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
@@ -48,12 +50,21 @@ struct Y
|
||||
Y( Y const& ) = delete;
|
||||
};
|
||||
|
||||
struct D
|
||||
{
|
||||
~D() {}
|
||||
};
|
||||
|
||||
inline bool operator==( D, D ) { return true; }
|
||||
|
||||
template<class V> static void test( V const & v )
|
||||
{
|
||||
V v2( v );
|
||||
|
||||
BOOST_TEST_EQ( v.index(), v2.index() );
|
||||
BOOST_TEST( v == v2 );
|
||||
|
||||
BOOST_TEST_TRAIT_TRUE((std::is_copy_constructible<V>));
|
||||
}
|
||||
|
||||
int main()
|
||||
@@ -115,6 +126,12 @@ int main()
|
||||
test( v );
|
||||
}
|
||||
|
||||
#if !BOOST_WORKAROUND( __GNUC__, < 5 )
|
||||
|
||||
test( variant<D>() );
|
||||
|
||||
#endif
|
||||
|
||||
{
|
||||
BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible<variant<int>>));
|
||||
BOOST_TEST_TRAIT_TRUE((std::is_nothrow_copy_constructible<variant<int const>>));
|
||||
|
||||
73
test/variant_hash.cpp
Normal file
73
test/variant_hash.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
|
||||
// Copyright 2020 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning( disable: 4244 ) // conversion from int to float, possible loss of data
|
||||
#endif
|
||||
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
|
||||
using namespace boost::variant2;
|
||||
|
||||
template<template<class...> class Hash, class T1, class T2, class T3> void test()
|
||||
{
|
||||
variant<T1, T2, T3> v1( in_place_index_t<0>{} );
|
||||
std::size_t h1 = Hash<decltype(v1)>()( v1 );
|
||||
|
||||
variant<T1, T2, T3> v2( in_place_index_t<1>{} );
|
||||
std::size_t h2 = Hash<decltype(v2)>()( v2 );
|
||||
|
||||
variant<T1, T2, T3> v3( in_place_index_t<2>{} );
|
||||
std::size_t h3 = Hash<decltype(v3)>()( v3 );
|
||||
|
||||
BOOST_TEST_NE( h1, h2 );
|
||||
BOOST_TEST_NE( h1, h3 );
|
||||
BOOST_TEST_NE( h2, h3 );
|
||||
}
|
||||
|
||||
template<template<class...> class Hash, class T> void test2()
|
||||
{
|
||||
variant<T> v1( 0 );
|
||||
std::size_t h1 = Hash<decltype(v1)>()( v1 );
|
||||
|
||||
variant<T> v2( 1 );
|
||||
std::size_t h2 = Hash<decltype(v2)>()( v2 );
|
||||
|
||||
variant<T> v3( 2 );
|
||||
std::size_t h3 = Hash<decltype(v3)>()( v3 );
|
||||
|
||||
BOOST_TEST_NE( h1, h2 );
|
||||
BOOST_TEST_NE( h1, h3 );
|
||||
BOOST_TEST_NE( h2, h3 );
|
||||
}
|
||||
|
||||
struct X {};
|
||||
|
||||
int main()
|
||||
{
|
||||
test<std::hash, monostate, monostate, monostate>();
|
||||
test<std::hash, int, int, float>();
|
||||
|
||||
test<boost::hash, monostate, monostate, monostate>();
|
||||
test<boost::hash, int, int, float>();
|
||||
|
||||
test2<std::hash, int>();
|
||||
test2<std::hash, float>();
|
||||
|
||||
test2<boost::hash, int>();
|
||||
test2<boost::hash, float>();
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910) && ( !defined(_LIBCPP_STD_VER) || _LIBCPP_STD_VER > 11 )
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE(( detail::is_hash_enabled<X> ));
|
||||
|
||||
#endif
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
103
test/variant_special.cpp
Normal file
103
test/variant_special.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright 2020 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1910
|
||||
# pragma warning(disable: 4503) // decorated name length exceeded
|
||||
#endif
|
||||
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
|
||||
#include <boost/mp11.hpp>
|
||||
using namespace boost::mp11;
|
||||
|
||||
//
|
||||
|
||||
using namespace boost::variant2;
|
||||
|
||||
struct D
|
||||
{
|
||||
~D() noexcept {}
|
||||
};
|
||||
|
||||
struct CC1
|
||||
{
|
||||
CC1( CC1 const& ) {}
|
||||
};
|
||||
|
||||
struct CC2
|
||||
{
|
||||
CC2( CC2 const& ) = delete;
|
||||
};
|
||||
|
||||
struct MC1
|
||||
{
|
||||
MC1( MC1 && ) {}
|
||||
};
|
||||
|
||||
struct MC2
|
||||
{
|
||||
MC2( MC2 && ) = delete;
|
||||
};
|
||||
|
||||
struct CA1
|
||||
{
|
||||
CA1& operator=( CA1 const& ) { return *this; }
|
||||
};
|
||||
|
||||
struct CA2
|
||||
{
|
||||
CA2& operator=( CA2 const& ) = delete;
|
||||
};
|
||||
|
||||
struct MA1
|
||||
{
|
||||
MA1& operator=( MA1 && ) { return *this; }
|
||||
};
|
||||
|
||||
struct MA2
|
||||
{
|
||||
MA2& operator=( MA2 && ) = delete;
|
||||
};
|
||||
|
||||
struct test
|
||||
{
|
||||
template<class... T> void operator()( mp_list<T...> ) const noexcept
|
||||
{
|
||||
using U = mp_inherit<T...>;
|
||||
|
||||
#if !BOOST_WORKAROUND( __GNUC__, < 5 )
|
||||
|
||||
BOOST_TEST_EQ( std::is_copy_constructible<variant<U>>::value, std::is_copy_constructible<U>::value );
|
||||
BOOST_TEST_EQ( std::is_nothrow_copy_constructible<variant<U>>::value, std::is_nothrow_copy_constructible<U>::value );
|
||||
|
||||
#endif
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
|
||||
|
||||
BOOST_TEST_EQ( std::is_move_constructible<variant<U>>::value, std::is_move_constructible<U>::value );
|
||||
|
||||
#else
|
||||
|
||||
BOOST_TEST_GE( std::is_move_constructible<variant<U>>::value, std::is_move_constructible<U>::value );
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_TEST_EQ( std::is_nothrow_move_constructible<variant<U>>::value, std::is_nothrow_move_constructible<U>::value );
|
||||
|
||||
BOOST_TEST_EQ( std::is_copy_assignable<variant<U>>::value, std::is_copy_constructible<U>::value && std::is_copy_assignable<U>::value );
|
||||
BOOST_TEST_EQ( std::is_nothrow_copy_assignable<variant<U>>::value, std::is_nothrow_copy_constructible<U>::value && std::is_copy_assignable<U>::value );
|
||||
|
||||
BOOST_TEST_EQ( std::is_move_assignable<variant<U>>::value, std::is_move_constructible<U>::value && std::is_move_assignable<U>::value );
|
||||
BOOST_TEST_EQ( std::is_nothrow_move_assignable<variant<U>>::value, std::is_nothrow_move_constructible<U>::value && std::is_move_assignable<U>::value );
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
mp_for_each< mp_power_set< mp_list<D, CC1, CC2, MC1, MC2, CA1, CA2, MA1, MA2> > >( test() );
|
||||
return boost::report_errors();
|
||||
}
|
||||
95
test/variant_trivial.cpp
Normal file
95
test/variant_trivial.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright 2020 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1910
|
||||
# pragma warning(disable: 4503) // decorated name length exceeded
|
||||
#endif
|
||||
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
|
||||
#include <boost/mp11.hpp>
|
||||
using namespace boost::mp11;
|
||||
|
||||
//
|
||||
|
||||
struct D
|
||||
{
|
||||
~D() noexcept {}
|
||||
};
|
||||
|
||||
struct CC1
|
||||
{
|
||||
CC1( CC1 const& ) noexcept {}
|
||||
};
|
||||
|
||||
struct CC2
|
||||
{
|
||||
CC2( CC2 const& ) = delete;
|
||||
};
|
||||
|
||||
struct MC1
|
||||
{
|
||||
MC1( MC1 && ) noexcept {}
|
||||
};
|
||||
|
||||
struct MC2
|
||||
{
|
||||
MC2( MC2 && ) = delete;
|
||||
};
|
||||
|
||||
struct CA1
|
||||
{
|
||||
CA1& operator=( CA1 const& ) noexcept { return *this; }
|
||||
};
|
||||
|
||||
struct CA2
|
||||
{
|
||||
CA2& operator=( CA2 const& ) = delete;
|
||||
};
|
||||
|
||||
struct MA1
|
||||
{
|
||||
MA1& operator=( MA1 && ) noexcept { return *this; }
|
||||
};
|
||||
|
||||
struct MA2
|
||||
{
|
||||
MA2& operator=( MA2 && ) = delete;
|
||||
};
|
||||
|
||||
using namespace boost::variant2;
|
||||
namespace v2d = boost::variant2::detail;
|
||||
|
||||
struct test
|
||||
{
|
||||
template<class... T> void operator()( mp_list<T...> ) const noexcept
|
||||
{
|
||||
using U = mp_inherit<T...>;
|
||||
|
||||
#if !BOOST_WORKAROUND( __GNUC__, < 5 )
|
||||
|
||||
BOOST_TEST_EQ( v2d::is_trivially_copy_constructible<variant<U>>::value, v2d::is_trivially_copy_constructible<U>::value );
|
||||
BOOST_TEST_EQ( v2d::is_trivially_copy_assignable<variant<U>>::value, std::is_trivially_destructible<U>::value && v2d::is_trivially_copy_constructible<U>::value && v2d::is_trivially_copy_assignable<U>::value );
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_TEST_EQ( std::is_trivially_destructible<variant<U>>::value, std::is_trivially_destructible<U>::value );
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION, < 50000)
|
||||
|
||||
BOOST_TEST_EQ( v2d::is_trivially_move_constructible<variant<U>>::value, v2d::is_trivially_move_constructible<U>::value );
|
||||
BOOST_TEST_EQ( v2d::is_trivially_move_assignable<variant<U>>::value, std::is_trivially_destructible<U>::value && v2d::is_trivially_move_constructible<U>::value && v2d::is_trivially_move_assignable<U>::value );
|
||||
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
mp_for_each< mp_power_set< mp_list<D, CC1, CC2, MC1, MC2, CA1, CA2, MA1, MA2> > >( test() );
|
||||
return boost::report_errors();
|
||||
}
|
||||
57
test/variant_visit_derived.cpp
Normal file
57
test/variant_visit_derived.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
// Copyright 2017, 2020 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning( disable: 4244 ) // conversion from float to int, possible loss of data
|
||||
#endif
|
||||
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <utility>
|
||||
|
||||
struct X: boost::variant2::variant<int, float>
|
||||
{
|
||||
#if BOOST_WORKAROUND( BOOST_MSVC, < 1930 )
|
||||
|
||||
template<class T> explicit X( T&& t ): variant( std::forward<T>( t ) ) {};
|
||||
|
||||
#else
|
||||
|
||||
using variant::variant;
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
template<class... T> struct Y: boost::variant2::variant<T...>
|
||||
{
|
||||
using boost::variant2::variant<T...>::variant;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
X v1( 1 );
|
||||
X const v2( 3.14f );
|
||||
|
||||
BOOST_TEST_EQ( (visit( []( int x1, float x2 ){ return (int)(x1 * 1000) + (int)(x2 * 100); }, v1, v2 )), 1314 );
|
||||
|
||||
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, v1, v2 );
|
||||
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, std::move(v1), std::move(v2) );
|
||||
}
|
||||
|
||||
{
|
||||
Y<int, float> v1( 1 );
|
||||
Y<int, float> const v2( 3.14f );
|
||||
|
||||
BOOST_TEST_EQ( (visit( []( int x1, float x2 ){ return (int)(x1 * 1000) + (int)(x2 * 100); }, v1, v2 )), 1314 );
|
||||
|
||||
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, v1, v2 );
|
||||
visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, std::move(v1), std::move(v2) );
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
Reference in New Issue
Block a user