diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp new file mode 100644 index 0000000..1da500e --- /dev/null +++ b/include/boost/variant2/variant.hpp @@ -0,0 +1,908 @@ +#ifndef BOOST_VARIANT2_VARIANT_HPP_INCLUDED +#define BOOST_VARIANT2_VARIANT_HPP_INCLUDED + +// Copyright 2015-2017 Peter Dimov. +// +// Distributed under the Boost Software License, Version 1.0. +// +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include +#include + +// + +namespace boost +{ +namespace variant2 +{ + +using namespace boost::mp11; + +// bad_variant_access + +class bad_variant_access: public std::exception +{ +public: + + bad_variant_access() noexcept + { + } + + char const * what() const noexcept + { + return "bad_variant_access"; + } +}; + +// + +template class variant; + +// variant_size + +template struct variant_size +{ +}; + +template struct variant_size: variant_size +{ +}; + +template struct variant_size: variant_size +{ +}; + +template struct variant_size: variant_size +{ +}; + +template /*inline*/ constexpr std::size_t variant_size_v = variant_size::value; + +template struct variant_size>: mp_size> +{ +}; + +// variant_alternative + +template struct variant_alternative; + +template using variant_alternative_t = typename variant_alternative::type; + +namespace detail +{ + template using var_alt_t = mp_invoke>; +} // namespace detail + +template struct variant_alternative +{ +}; + +template struct variant_alternative: mp_defer< variant2::detail::var_alt_t, mp_size_t, T, mp_quote> +{ +}; + +template struct variant_alternative: mp_defer< variant2::detail::var_alt_t, mp_size_t, T, mp_quote> +{ +}; + +template struct variant_alternative: mp_defer< variant2::detail::var_alt_t, mp_size_t, T, mp_quote> +{ +}; + +template struct variant_alternative>: mp_defer, mp_size_t> +{ +}; + +// holds_alternative + +template constexpr bool holds_alternative( variant const& v ) noexcept +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + return v.index() == mp_find, U>::value; +} + +// get + +template constexpr variant_alternative_t>& get(variant& v) +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + + return v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ); + +#else + + return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); + +#endif +} + +template constexpr variant_alternative_t>&& get(variant&& v) +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + + return std::move( v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ) ); + +#else + + return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); + +#endif +} + +template constexpr variant_alternative_t const>& get(variant const& v) +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + + return v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ); + +#else + + return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); + +#endif +} + +template constexpr variant_alternative_t const>&& get(variant const&& v) +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + + return std::move( v.index() == I? v._get_impl( mp_size_t() ): ( throw bad_variant_access(), v._get_impl( mp_size_t() ) ) ); + +#else + + return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); + +#endif +} + +// get + +template constexpr U& get(variant& v) +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + + return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); +} + +template constexpr U&& get(variant&& v) +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + + return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); +} + +template constexpr U const& get(variant const& v) +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + + return v.index() == I? v._get_impl( mp_size_t() ): throw bad_variant_access(); +} + +template constexpr U const&& get(variant const&& v) +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + + return v.index() == I? std::move( v._get_impl( mp_size_t() ) ): throw bad_variant_access(); +} + +// get_if + +template constexpr std::add_pointer_t>> get_if(variant* v) noexcept +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + return v->index() == I? &v->_get_impl( mp_size_t() ): 0; +} + +template constexpr std::add_pointer_t>> get_if(variant const * v) noexcept +{ + static_assert( I < sizeof...(T), "Index out of bounds" ); + return v->index() == I? &v->_get_impl( mp_size_t() ): 0; +} + +template constexpr std::add_pointer_t get_if(variant* v) noexcept +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + + return v->index() == I? &v->_get_impl( mp_size_t() ): 0; +} + +template constexpr std::add_pointer_t get_if(variant const * v) noexcept +{ + static_assert( mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); + constexpr auto I = mp_find, U>::value; + + return v->index() == I? &v->_get_impl( mp_size_t() ): 0; +} + +// + +namespace detail +{ + +// variant_storage + +template union variant_storage_impl; + +template using variant_storage = variant_storage_impl...>, T...>; + +template union variant_storage_impl +{ +}; + +// not all trivially destructible +template union variant_storage_impl +{ + T1 first_; + variant_storage rest_; + + template constexpr explicit variant_storage_impl( mp_size_t<0>, A&&... a ): first_( std::forward(a)... ) + { + } + + template constexpr explicit variant_storage_impl( mp_size_t, A&&... a ): rest_( mp_size_t(), std::forward(a)... ) + { + } + + ~variant_storage_impl() + { + } + + template void emplace( mp_size_t<0>, A&&... a ) noexcept + { + ::new( &first_ ) T1( std::forward(a)... ); + } + + template void emplace( mp_size_t, A&&... a ) noexcept + { + rest_.emplace( mp_size_t(), std::forward(a)... ); + } + + constexpr T1& get( mp_size_t<0> ) noexcept { return first_; } + constexpr T1 const& get( mp_size_t<0> ) const noexcept { return first_; } + + template constexpr mp_at_c, I-1>& get( mp_size_t ) noexcept { return rest_.get( mp_size_t() ); } + template constexpr mp_at_c, I-1> const& get( mp_size_t ) const noexcept { return rest_.get( mp_size_t() ); } +}; + +// all trivially destructible +template union variant_storage_impl +{ + T1 first_; + variant_storage rest_; + + template constexpr explicit variant_storage_impl( mp_size_t<0>, A&&... a ): first_( std::forward(a)... ) + { + } + + template constexpr explicit variant_storage_impl( mp_size_t, A&&... a ): rest_( mp_size_t(), std::forward(a)... ) + { + } + + template void emplace( mp_size_t<0>, A&&... a ) noexcept + { + ::new( &first_ ) T1( std::forward(a)... ); + } + + template void emplace( mp_size_t, A&&... a ) noexcept + { + rest_.emplace( mp_size_t(), std::forward(a)... ); + } + + constexpr T1& get( mp_size_t<0> ) noexcept { return first_; } + constexpr T1 const& get( mp_size_t<0> ) const noexcept { return first_; } + + template constexpr mp_at_c, I-1>& get( mp_size_t ) noexcept { return rest_.get( mp_size_t() ); } + template constexpr mp_at_c, I-1> const& get( mp_size_t ) const noexcept { return rest_.get( mp_size_t() ); } +}; + +// resolve_overload_* + +template struct overload; + +template<> struct overload<> +{ + void operator()() const; +}; + +template struct overload: overload +{ + using overload::operator(); + mp_identity operator()(T1) const; +}; + +#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 ) + +template struct resolve_overload_type_impl +{ + using type = decltype( overload()(std::declval()) ); +}; + +template using resolve_overload_type = typename resolve_overload_type_impl::type::type; + +#else + +template using resolve_overload_type = typename decltype( overload()(std::declval()) )::type; + +#endif + +template using resolve_overload_index = mp_find, resolve_overload_type>; + +// variant_base + +template struct variant_base_impl; // trivially destructible, single buffered +template using variant_base = variant_base_impl...>, mp_all...>, T...>; + +struct none {}; + +// trivially destructible, single buffered +template struct variant_base_impl +{ + int ix_; + variant_storage st1_; + + constexpr variant_base_impl(): ix_( 0 ), st1_( mp_size_t<0>() ) + { + } + + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp_size_t(), std::forward(a)... ) + { + } + + template constexpr mp_at_c, I>& _get_impl( mp_size_t i ) noexcept + { + size_t const J = I+1; + + assert( ix_ == J ); + + return st1_.get( mp_size_t() ); + } + + template constexpr mp_at_c, I> const& _get_impl( mp_size_t i ) const noexcept + { + size_t const J = I+1; + + assert( ix_ == J ); + + return st1_.get( mp_size_t() ); + } + + template void emplace( A&&... a ) + { + size_t const J = I+1; + + using U = mp_at_c, I>; + + if( std::is_nothrow_constructible::value ) + { + st1_.emplace( mp_size_t(), std::forward(a)... ); + ix_ = J; + } + else + { + U tmp( std::forward(a)... ); + + st1_.emplace( mp_size_t(), std::move(tmp) ); + ix_ = J; + } + } +}; + +// trivially destructible, double buffered +template struct variant_base_impl +{ + int ix_; + variant_storage st1_; + variant_storage st2_; + + constexpr variant_base_impl(): ix_( 0 ), st1_( mp_size_t<0>() ), st2_( mp_size_t<0>() ) + { + } + + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp_size_t(), std::forward(a)... ), st2_( mp_size_t<0>() ) + { + } + + template constexpr mp_at_c, I>& _get_impl( mp_size_t i ) noexcept + { + size_t const J = I+1; + + assert( ix_ == J || -ix_ == J ); + + constexpr mp_size_t j{}; + return ix_ >= 0? st1_.get( j ): st2_.get( j ); + } + + template constexpr mp_at_c, I> const& _get_impl( mp_size_t i ) const noexcept + { + size_t const J = I+1; + + assert( ix_ == J || -ix_ == J ); + + constexpr mp_size_t j{}; + return ix_ >= 0? st1_.get( j ): st2_.get( j ); + } + + template void emplace( A&&... a ) + { + size_t const J = I+1; + + if( ix_ >= 0 ) + { + st2_.emplace( mp_size_t(), std::forward(a)... ); + ix_ = -static_cast( J ); + } + else + { + st1_.emplace( mp_size_t(), std::forward(a)... ); + ix_ = J; + } + } +}; + +// not trivially destructible, single buffered +template struct variant_base_impl +{ + int ix_; + variant_storage st1_; + + constexpr variant_base_impl(): ix_( 0 ), st1_( mp_size_t<0>() ) + { + } + + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp_size_t(), std::forward(a)... ) + { + } + + void _destroy() noexcept + { + mp_for_each>([&]( auto I ){ + + using U = mp_at_c, I>; + constexpr auto J = decltype(I)::value + 1; + + if( J == ix_ ) + { + st1_.get( mp_size_t() ).~U(); + } + + }); + } + + ~variant_base_impl() noexcept + { + _destroy(); + } + + template constexpr mp_at_c, I>& _get_impl( mp_size_t i ) noexcept + { + size_t const J = I+1; + + assert( ix_ == J ); + + return st1_.get( mp_size_t() ); + } + + template constexpr mp_at_c, I> const& _get_impl( mp_size_t i ) const noexcept + { + size_t const J = I+1; + + assert( ix_ == J ); + + return st1_.get( mp_size_t() ); + } + + template void emplace( A&&... a ) + { + size_t const J = I+1; + + using U = mp_at_c, I>; + + if( std::is_nothrow_constructible::value ) + { + _destroy(); + st1_.emplace( mp_size_t(), std::forward(a)... ); + + ix_ = J; + } + else + { + assert( std::is_nothrow_move_constructible::value ); + + U tmp( std::forward(a)... ); + + _destroy(); + st1_.emplace( mp_size_t(), std::move(tmp) ); + + ix_ = J; + } + } +}; + +// not trivially destructible, double buffered +template struct variant_base_impl +{ + int ix_; + variant_storage st1_; + variant_storage st2_; + + constexpr variant_base_impl(): ix_( 0 ), st1_( mp_size_t<0>() ), st2_( mp_size_t<0>() ) + { + } + + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp_size_t(), std::forward(a)... ), st2_( mp_size_t<0>() ) + { + } + + void _destroy() noexcept + { + mp_for_each>([&]( auto I ){ + + using U = mp_at_c, I>; + constexpr auto J = decltype(I)::value + 1; + + if( ix_ > 0 && J == ix_ ) + { + st1_.get( mp_size_t() ).~U(); + } + + if( ix_ < 0 && J == -ix_ ) + { + st2_.get( mp_size_t() ).~U(); + } + + }); + } + + ~variant_base_impl() noexcept + { + _destroy(); + } + + template constexpr mp_at_c, I>& _get_impl( mp_size_t i ) noexcept + { + size_t const J = I+1; + + assert( ix_ == J || -ix_ == J ); + + constexpr mp_size_t j{}; + return ix_ >= 0? st1_.get( j ): st2_.get( j ); + } + + template constexpr mp_at_c, I> const& _get_impl( mp_size_t i ) const noexcept + { + size_t const J = I+1; + + assert( ix_ == J || -ix_ == J ); + + constexpr mp_size_t j{}; + return ix_ >= 0? st1_.get( j ): st2_.get( j ); + } + + template void emplace( A&&... a ) + { + size_t const J = I+1; + + if( ix_ >= 0 ) + { + st2_.emplace( mp_size_t(), std::forward(a)... ); + _destroy(); + + ix_ = -static_cast( J ); + } + else + { + st1_.emplace( mp_size_t(), std::forward(a)... ); + _destroy(); + + ix_ = J; + } + } +}; + +} // namespace detail + +// in_place_type_t + +template struct in_place_type_t +{ +}; + +// in_place_index_t + +template struct in_place_index_t +{ +}; + +// variant + +template class variant: private variant2::detail::variant_base +{ +private: + + using variant_base = variant2::detail::variant_base; + +public: + + // constructors + + constexpr variant() + noexcept( std::is_nothrow_default_constructible< mp_first> >::value ) + : variant_base( mp_size_t<0>() ) + { + } + + variant( variant const& r ) + noexcept( mp_all...>::value ) + { + mp_for_each>([&]( auto I ){ + + if( I == r.index() ) + { + ::new( static_cast(this) ) variant_base( I, r._get_impl( I ) ); + } + + }); + } + + variant( variant && r ) + noexcept( mp_all...>::value ) + { + mp_for_each>([&]( auto I ){ + + if( I == r.index() ) + { + ::new( static_cast(this) ) variant_base( I, std::move( r._get_impl( I ) ) ); + } + + }); + } + + template constexpr variant( U&& u ) + noexcept( std::is_nothrow_constructible< variant2::detail::resolve_overload_type, U >::value ) + : variant_base( variant2::detail::resolve_overload_index(), std::forward(u) ) + { + } + + template, U>> + constexpr explicit variant( in_place_type_t, A&&... a ): variant_base( I(), std::forward(a)... ) + { + } + + template + constexpr explicit variant( in_place_type_t, std::initializer_list, A&&... a ); + + template + constexpr explicit variant( in_place_index_t, A&&... a ): variant_base( mp_size_t(), std::forward(a)... ) + { + } + + template + constexpr explicit variant( in_place_index_t, std::initializer_list, A&&... ); + + // assignment + variant& operator=( variant const & r ) + { + mp_for_each>([&]( auto I ){ + + constexpr auto J = decltype(I)::value; + + if( J == r.index() ) + { + if( index() == J ) + { + get(*this) = get(r); + } + else + { + variant_base::template emplace( get(r) ); + } + } + + }); + + return *this; + } + + variant& operator=( variant&& r ) noexcept( mp_all..., std::is_nothrow_move_assignable...>::value ) + { + mp_for_each>([&]( auto I ){ + + constexpr auto J = decltype(I)::type::value; + + if( J == r.index() ) + { + if( index() == J ) + { + get(*this) = get(std::move(r)); + } + else + { + variant_base::template emplace( get(std::move(r)) ); + } + } + + }); + + return *this; + } + + template, variant>::value>, + class V = variant2::detail::resolve_overload_type, + class E2 = std::enable_if_t::value && std::is_constructible::value> + > + variant& operator=( U&& u ) // noexcept(see below ); + { + std::size_t const I = variant2::detail::resolve_overload_index::value; + + if( index() == I ) + { + _get_impl( mp_size_t() ) = std::forward(u); + } + else + { + this->template emplace( std::forward(u) ); + } + + return *this; + } + + // modifiers + // using variant_base::emplace; + + template, U>> U& emplace( A&&... a ) + { + variant_base::template emplace( std::forward(a)... ); + return _get_impl( I() ); + } + + template U& emplace( std::initializer_list il, A&&... a ); + + template variant_alternative_t>& emplace( A&&... a ) + { + variant_base::template emplace( std::forward(a)... ); + return _get_impl( mp_size_t() ); + } + + template variant_alternative_t>& emplace( std::initializer_list il, A&&... a ); + + // value status + + constexpr size_t index() const noexcept + { + return this->ix_ >= 0? this->ix_ - 1 : -this->ix_ - 1; + } + + // swap + + void swap( variant& r ); // noexcept( ... ) + + // private accessors + + constexpr int _real_index() const noexcept + { + return this->ix_; + } + + using variant_base::_get_impl; +}; + +// relational operators +template constexpr bool operator==( variant const & v, variant const & w ) +{ + if( v.index() != w.index() ) return false; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) == get(w); + + }); + + assert( false ); + return false; +} + +template constexpr bool operator!=( variant const & v, variant const & w ) +{ + if( v.index() != w.index() ) return true; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) != get(w); + + }); + + assert( false ); + return true; +} + +template constexpr bool operator<( variant const & v, variant const & w ) +{ + if( v.index() < w.index() ) return true; + if( v.index() > w.index() ) return false; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) < get(w); + + }); + + assert( false ); + return false; +} + +template constexpr bool operator>( variant const & v, variant const & w ) +{ + if( v.index() > w.index() ) return true; + if( v.index() < w.index() ) return false; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) > get(w); + + }); + + assert( false ); + return false; +} + +template constexpr bool operator<=( variant const & v, variant const & w ) +{ + if( v.index() < w.index() ) return true; + if( v.index() > w.index() ) return false; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) <= get(w); + + }); + + assert( false ); + return false; +} + +template constexpr bool operator>=( variant const & v, variant const & w ) +{ + if( v.index() > w.index() ) return true; + if( v.index() < w.index() ) return false; + + mp_for_each>([&]( auto I ){ + + if( I == v.index() ) return get(v) >= get(w); + + }); + + assert( false ); + return false; +} + +// visitation +template constexpr void visit( Visitor&&, Variants&&... ); + +// specialized algorithms +template void swap( variant & v, variant & w ); // noexcept(see below ); + +} // namespace variant2 +} // namespace boost + +#endif // #ifndef BOOST_VARIANT2_VARIANT_HPP_INCLUDED diff --git a/meta/libraries.json b/meta/libraries.json new file mode 100644 index 0000000..50915a9 --- /dev/null +++ b/meta/libraries.json @@ -0,0 +1,14 @@ +{ + "key": "variant2", + "name": "Variant2", + "authors": [ + "Peter Dimov" + ], + "maintainers": [ + "Peter Dimov " + ], + "description": "A never-valueless implementation of std::variant.", + "category": [ + "Containers", "Data" + ] +} diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 0000000..f114533 --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,15 @@ +# Boost.Variant2 Library Test Jamfile +# +# Copyright 2015-2017 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 + +import testing ; +import ../../config/checks/config : requires ; + +REQ = ; #[ requires cxx11_variadic_templates cxx11_template_aliases cxx11_decltype cxx11_hdr_type_traits ] ; + +run variant_size.cpp : : : $(REQ) ; +run variant_alternative.cpp : : : $(REQ) ; diff --git a/test/variant_alternative.cpp b/test/variant_alternative.cpp new file mode 100644 index 0000000..44e2a7a --- /dev/null +++ b/test/variant_alternative.cpp @@ -0,0 +1,90 @@ + +// Copyright 2017 Peter Dimov. +// +// Distributed under the Boost Software License, Version 1.0. +// +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; +using namespace boost::mp11; + +template using var_alt_t = variant_alternative_t; + +int main() +{ + + BOOST_TEST_TRAIT_TRUE((std::is_same>, void>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, void const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, void volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, void const volatile>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same>, void>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, void const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, void volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, void const volatile>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same>, int>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, int const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, int volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, int const volatile>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same>, void>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, void const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, void volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, void const volatile>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same>, int>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, int const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, int volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, int const volatile>)); + + BOOST_TEST_TRAIT_TRUE((std::is_same>, float>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const>, float const>)); + BOOST_TEST_TRAIT_TRUE((std::is_same volatile>, float volatile>)); + BOOST_TEST_TRAIT_TRUE((std::is_same const volatile>, float const volatile>)); + + variant_alternative<0, void>(); + variant_alternative<0, void const>(); + variant_alternative<0, void volatile>(); + variant_alternative<0, void const volatile>(); + + variant_alternative<0, variant<>>(); + variant_alternative<0, variant<> const>(); + variant_alternative<0, variant<> volatile>(); + variant_alternative<0, variant<> const volatile>(); + + variant_alternative<1, variant>(); + variant_alternative<1, variant const>(); + variant_alternative<1, variant volatile>(); + variant_alternative<1, variant const volatile>(); + + BOOST_TEST_TRAIT_FALSE((mp_valid, void>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, void const>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, void volatile>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, void const volatile>)); + + BOOST_TEST_TRAIT_FALSE((mp_valid, variant<>>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant<> const>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant<> volatile>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant<> const volatile>)); + + BOOST_TEST_TRAIT_TRUE((mp_valid, variant>)); + BOOST_TEST_TRAIT_TRUE((mp_valid, variant const>)); + BOOST_TEST_TRAIT_TRUE((mp_valid, variant volatile>)); + BOOST_TEST_TRAIT_TRUE((mp_valid, variant const volatile>)); + + BOOST_TEST_TRAIT_FALSE((mp_valid, variant>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant const>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant volatile>)); + BOOST_TEST_TRAIT_FALSE((mp_valid, variant const volatile>)); + + return boost::report_errors(); +} diff --git a/test/variant_size.cpp b/test/variant_size.cpp new file mode 100644 index 0000000..3d59682 --- /dev/null +++ b/test/variant_size.cpp @@ -0,0 +1,65 @@ + +// Copyright 2017 Peter Dimov. +// +// Distributed under the Boost Software License, Version 1.0. +// +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include + +using namespace boost::variant2; +using namespace boost::mp11; + +template using var_size_t = mp_size_t::value>; + +int main() +{ + + BOOST_TEST_EQ( (variant_size>::value), 0 ); + BOOST_TEST_EQ( (variant_size const>::value), 0 ); + BOOST_TEST_EQ( (variant_size volatile>::value), 0 ); + BOOST_TEST_EQ( (variant_size const volatile>::value), 0 ); + + BOOST_TEST_EQ( (variant_size>::value), 1 ); + BOOST_TEST_EQ( (variant_size const>::value), 1 ); + BOOST_TEST_EQ( (variant_size volatile>::value), 1 ); + BOOST_TEST_EQ( (variant_size const volatile>::value), 1 ); + + BOOST_TEST_EQ( (variant_size>::value), 2 ); + BOOST_TEST_EQ( (variant_size const>::value), 2 ); + BOOST_TEST_EQ( (variant_size volatile>::value), 2 ); + BOOST_TEST_EQ( (variant_size const volatile>::value), 2 ); + + BOOST_TEST_EQ( (variant_size>::value), 3 ); + BOOST_TEST_EQ( (variant_size const>::value), 3 ); + BOOST_TEST_EQ( (variant_size volatile>::value), 3 ); + BOOST_TEST_EQ( (variant_size const volatile>::value), 3 ); + + BOOST_TEST_EQ( (variant_size>::value), 4 ); + BOOST_TEST_EQ( (variant_size const>::value), 4 ); + BOOST_TEST_EQ( (variant_size volatile>::value), 4 ); + BOOST_TEST_EQ( (variant_size const volatile>::value), 4 ); + + variant_size(); + variant_size(); + variant_size(); + variant_size(); + + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + BOOST_TEST_TRAIT_FALSE((mp_valid)); + + BOOST_TEST_TRAIT_TRUE((mp_valid>)); + BOOST_TEST_TRAIT_TRUE((mp_valid const>)); + BOOST_TEST_TRAIT_TRUE((mp_valid volatile>)); + BOOST_TEST_TRAIT_TRUE((mp_valid const volatile>)); + + return boost::report_errors(); +}