Compare commits

...

20 Commits

Author SHA1 Message Date
Peter Dimov
a0b499bc3b Use copy_cv_ref in apply_cv_ref instead of variant_alternative_t 2019-02-22 01:57:09 +02:00
Peter Dimov
c1287f9e95 Fix variant_alternative for g++ 4.8 2019-02-21 23:06:24 +02:00
Peter Dimov
34933c35bd Use variant_alternative_t directly for references 2019-02-21 22:42:21 +02:00
Peter Dimov
d8cd270268 Add reference specializations to variant_alternative 2019-02-21 22:22:07 +02:00
Peter Dimov
87a2e88edb Use variant_size directly with references 2019-02-21 22:03:56 +02:00
Peter Dimov
cf3ea64b45 Add reference specializations to variant_size 2019-02-21 21:57:39 +02:00
Peter Dimov
f67a6bd2ae Remove variant2:: qualifications, detail is no longer ambiguous 2019-02-21 21:40:06 +02:00
Peter Dimov
f3e101a841 Remove using namespace boost::mp11 2019-02-21 20:37:20 +02:00
Peter Dimov
5911e80f4f Update documentation 2019-02-21 06:42:06 +02:00
Peter Dimov
24fae0f542 Fix SFINAE conditions on emplace<U> 2019-02-18 20:40:17 +02:00
Peter Dimov
8f2ef7ddc1 Fix line indent 2019-02-18 20:00:02 +02:00
Peter Dimov
58709c2922 Change mp_invoke to mp_invoke_q 2019-02-18 19:58:20 +02:00
Peter Dimov
16027c5447 Add to documentation 2019-02-18 19:51:23 +02:00
Peter Dimov
3fb89b9f5a Merge branch 'develop' into feature/doc 2018-10-25 02:56:49 +03:00
Peter Dimov
33f28c739f Fix test/variant_move_construct_cx.cpp 2018-10-24 19:03:00 +03:00
Peter Dimov
c1d2d991b4 Fix test/variant_copy_construct_cx.cpp 2018-10-24 18:58:23 +03:00
Peter Dimov
7c7779621f Initial documentation commit (WIP) 2018-10-24 18:34:17 +03:00
Peter Dimov
f14228d996 Minor README fixes 2018-10-19 01:24:26 +03:00
Peter Dimov
3fb00763cb Fix typos 2018-10-18 20:24:06 +03:00
Peter Dimov
ebc8959049 Update README 2018-10-18 19:55:15 +03:00
14 changed files with 1433 additions and 267 deletions

View File

@@ -1,34 +1,64 @@
# variant2
This repository contains a never-valueless C++14 implementation of [std::variant](http://en.cppreference.com/w/cpp/utility/variant) in [variant.hpp](include/boost/variant2/variant.hpp) and an implementation of `expected<T, E...>` in [expected.hpp](include/boost/variant2/expected.hpp) that is an extended version of `expected<T, E>` as proposed in [P0323R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0323r1.pdf) and the subsequent [D0323R2](https://github.com/viboes/std-make/blob/master/doc/proposal/expected/d0323r2.md).
This repository contains a never-valueless C++11/14/17 implementation of
[std::variant](http://en.cppreference.com/w/cpp/utility/variant) in
[variant.hpp](include/boost/variant2/variant.hpp) and an implementation of
`expected<T, E...>` in [expected.hpp](include/boost/variant2/expected.hpp)
that is an extended version of `expected<T, E>` as proposed in
[P0323R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0323r1.pdf)
and the subsequent
[D0323R2](https://github.com/viboes/std-make/blob/master/doc/proposal/expected/d0323r2.md).
The code requires [mp11](https://github.com/pdimov/mp11) and Boost.Config. The repository is intended to be placed into the `libs/variant2` directory of a Boost clone or release, with mp11 in `libs/mp11`, but the headers will also work standalone if [mp11.hpp](https://github.com/pdimov/mp11/blob/master/include/boost/mp11.hpp) or [mp11_single.hpp](https://github.com/pdimov/mp11/blob/master/include/boost/mp11_single.hpp) is included beforehand.
The code requires [Boost.Mp11](https://github.com/boostorg/mp11) and
Boost.Config.
The repository is intended to be placed into the `libs/variant2` directory of
a Boost clone or release, but the header `variant.hpp` will also work
[standalone](https://godbolt.org/z/6LSV3Z).
Supported compilers:
* g++ 5 or later with -std=c++14 or -std=c++1z
* clang++ 3.5 or later with -std=c++14 or -std=c++1z
* Visual Studio 2017
* g++ 4.8 or later with `-std=c++11` or above
* clang++ 3.5 or later with `-std=c++11` or above
* Visual Studio 2015, 2017
Tested on [Travis](https://travis-ci.org/pdimov/variant2/) and [Appveyor](https://ci.appveyor.com/project/pdimov/variant2/).
Tested on [Travis](https://travis-ci.org/pdimov/variant2/) and
[Appveyor](https://ci.appveyor.com/project/pdimov/variant2/).
## variant.hpp
The class `boost::variant2::variant<T...>` is an almost conforming implementation of `std::variant` with the following differences:
The class `boost::variant2::variant<T...>` is an almost conforming
implementation of `std::variant` with the following differences:
* A converting constructor from, e.g. `variant<int, float>` to `variant<float, double, int>` is provided as an extension;
* The reverse operation, going from `variant<float, double, int>` to `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.)
* A converting constructor from, e.g. `variant<int, float>` to
`variant<float, double, int>` is provided as an extension;
* The reverse operation, going from `variant<float, double, int>` to
`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 trivial when all contained types are trivial.
To avoid going into a valueless-by-exception state, this implementation falls back to using double storage unless
To avoid going into a valueless-by-exception state, this implementation falls
back to using double storage unless
* all the contained types are nothrow move constructible, or
* the first alternative is the type `valueless`.
* one of the alternatives is the type `monostate`,
* one of the alternatives has a nonthrowing default constructor, or
* all the contained types are nothrow move constructible.
If the second bullet doesn't hold, but the first does, the variant uses single storage, but `emplace` constructs a temporary and moves it into place if the construction of the object can throw. In case this is undesirable, one can force `emplace` into always constructing in-place by adding `valueless` as a first alternative.
If the first two bullets don't hold, but the third does, the variant uses
single storage, but `emplace` constructs a temporary and moves it into place
if the construction of the object can throw. In case this is undesirable, one
can force `emplace` into always constructing in-place by adding `monostate` as
one of the alternatives.
## expected.hpp
The class `boost::variant2::expected<T, E...>` represents the return type of an operation that may potentially fail. It contains either the expected result of type `T`, or a reason for the failure, of one of the error types in `E...`. Internally, this is stored as `variant<T, E...>`.
The class `boost::variant2::expected<T, E...>` represents the return type of
an operation that may potentially fail. It contains either the expected result
of type `T`, or a reason for the failure, of one of the error types in `E...`.
Internally, this is stored as `variant<T, E...>`.
See [its documentation](doc/expected.md) for more information.
Note that, while `variant` is production quality, `expected` is still a work
in progress and has no test suite yet.

2
doc/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/html/
/pdf/

23
doc/Jamfile Normal file
View File

@@ -0,0 +1,23 @@
# Copyright 2017, 2018 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 asciidoctor ;
html variant.html : variant.adoc ;
install html_ : variant.html : <location>html ;
pdf variant.pdf : variant.adoc ;
explicit variant.pdf ;
install pdf_ : variant.pdf : <location>pdf ;
explicit pdf_ ;
###############################################################################
alias boostdoc ;
explicit boostdoc ;
alias boostrelease : html_ ;
explicit boostrelease ;

View File

@@ -0,0 +1,5 @@
<style>
*:not(pre)>code { background: none; color: #600000; }
</style>

23
doc/variant.adoc Normal file
View File

@@ -0,0 +1,23 @@
////
Copyright 2018 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
////
# Boost.Variant2: A never valueless variant type
Peter Dimov
:toc: left
:toclevels: 4
:idprefix:
:docinfo: private-footer
:leveloffset: +1
include::variant/overview.adoc[]
include::variant/reference.adoc[]
include::variant/copyright.adoc[]
:leveloffset: -1

View File

@@ -0,0 +1,15 @@
////
Copyright 2018, 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
////
[#copyright]
# Copyright and License
:idprefix:
This documentation is copyright 2018, 2019 Peter Dimov and is distributed under
the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].

40
doc/variant/overview.adoc Normal file
View File

@@ -0,0 +1,40 @@
////
Copyright 2018 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
////
[#overview]
# Overview
:idprefix:
This library implements a type-safe discriminated union (variant) type,
`variant<T...>`, that almost conforms to the {cpp}17 Standard's
http://en.cppreference.com/w/cpp/utility/variant[`std::variant<T...>`]. The
main differences between the two are:
* `variant<T...>` does not have a valueless-by-exception state;
* A converting constructor from, e.g. `variant<int, float>` to
`variant<float, double, int>` is provided as an extension;
* The reverse operation, going from `variant<float, double, int>` to
`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 trivial when all contained types are trivial, as
mandated by {cpp}17.
To avoid the valueless-by-exception state, this implementation falls
back to using double storage unless
* one of the alternatives is the type `monostate`,
* one of the alternatives has a nonthrowing default constructor, or
* all the contained types are nothrow move constructible.
If the first two bullets don't hold, but the third does, the variant uses
single storage, but `emplace` constructs a temporary and moves it into place
if the construction of the object can throw. In case this is undesirable, one
can force `emplace` into always constructing in-place by adding `monostate` as
one of the alternatives.

847
doc/variant/reference.adoc Normal file
View File

@@ -0,0 +1,847 @@
////
Copyright 2018, 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
////
[#reference]
# Reference
:idprefix: ref_
## <boost/variant2/variant.hpp>
### Synopsis
```
namespace boost {
namespace variant2 {
// in_place_type
template<class T> struct in_place_type_t {};
template<class T> constexpr in_place_type_t<T> in_place_type{};
// in_place_index
template<std::size_t I> struct in_place_index_t {};
template<std::size_t I> constexpr in_place_index_t<I> in_place_index{};
// variant
template<class... T> class variant;
// variant_size
template<class T> struct variant_size {};
template<class T> struct variant_size<T const>: variant_size<T> {};
template<class T> struct variant_size<T volatile>: variant_size<T> {};
template<class T> struct variant_size<T const volatile>: variant_size<T> {};
template<class T>
inline constexpr size_t variant_size_v = variant_size<T>::value;
template<class... T>
struct variant_size<variant<T...>>:
std::integral_constant<std::size_t, sizeof...(T)> {};
// variant_alternative
template<size_t I, class T> struct variant_alternative {};
template<size_t I, class T> struct variant_alternative<I, T const>;
template<size_t I, class T> struct variant_alternative<I, T volatile>;
template<size_t I, class T> struct variant_alternative<I, T const volatile>;
template<size_t I, class T>
using variant_alternative_t = typename variant_alternative<I, T>::type;
template<size_t I, class... T>
struct variant_alternative<I, variant<T...>>;
// variant_npos
constexpr std::size_t variant_npos = -1;
// holds_alternative
template<class U, class... T>
constexpr bool holds_alternative(const variant<T...>& v) noexcept;
// get
template<size_t I, class... T>
constexpr variant_alternative_t<I, variant<T...>>&
get(variant<T...>& v);
template<size_t I, class... T>
constexpr variant_alternative_t<I, variant<T...>>&&
get(variant<T...>&& v);
template<size_t I, class... T>
constexpr const variant_alternative_t<I, variant<T...>>&
get(const variant<T...>& v);
template<size_t I, class... T>
constexpr const variant_alternative_t<I, variant<T...>>&&
get(const variant<T...>&& v);
template<class U, class... T>
constexpr U& get(variant<T...>& v);
template<class U, class... T>
constexpr U&& get(variant<T...>&& v);
template<class U, class... T>
constexpr const U& get(const variant<T...>& v);
template<class U, class... T>
constexpr const U&& get(const variant<T...>&& v);
// get_if
template<size_t I, class... T>
constexpr add_pointer_t<variant_alternative_t<I, variant<T...>>>
get_if(variant<T...>* v) noexcept;
template<size_t I, class... T>
constexpr add_pointer_t<const variant_alternative_t<I, variant<T...>>>
get_if(const variant<T...>* v) noexcept;
template<class T, class... T>
constexpr add_pointer_t<T>
get_if(variant<T...>* v) noexcept;
template<class T, class... T>
constexpr add_pointer_t<const T>
get_if(const variant<T...>* v) noexcept;
// relational operators
template<class... T>
constexpr bool operator==(const variant<T...>& v, const variant<T...>& w);
template<class... T>
constexpr bool operator!=(const variant<T...>& v, const variant<T...>& w);
template<class... T>
constexpr bool operator<(const variant<T...>& v, const variant<T...>& w);
template<class... T>
constexpr bool operator>(const variant<T...>& v, const variant<T...>& w);
template<class... T>
constexpr bool operator<=(const variant<T...>& v, const variant<T...>& w);
template<class... T>
constexpr bool operator>=(const variant<T...>& v, const variant<T...>& w);
// visit
template<class F, class... V>
constexpr /*see below*/ visit(F&& f, V&&... v);
// monostate
struct monostate {};
constexpr bool operator==(monostate, monostate) noexcept { return true; }
constexpr bool operator!=(monostate, monostate) noexcept { return false; }
constexpr bool operator<(monostate, monostate) noexcept { return false; }
constexpr bool operator>(monostate, monostate) noexcept { return false; }
constexpr bool operator<=(monostate, monostate) noexcept { return true; }
constexpr bool operator>=(monostate, monostate) noexcept { return true; }
// swap
template<class... T>
void swap(variant<T...>& v, variant<T...>& w) noexcept( /*see below*/ );
// bad_variant_access
class bad_variant_access;
} // namespace variant2
} // namespace boost
```
### variant
```
namespace boost {
namespace variant2 {
template<class... T> class variant
{
public:
// constructors
constexpr variant() noexcept( /*see below*/ );
constexpr variant( variant const & r ) noexcept( /*see below*/ );
constexpr variant( variant&& r ) noexcept( /*see below*/ );
template<class U>
constexpr variant( U&& u ) noexcept( /*see below*/ );
template<class U, class... A>
constexpr explicit variant( in_place_type_t<U>, A&&... a );
template<class U, class V, class... A>
constexpr explicit variant( in_place_type_t<U>,
std::initializer_list<V> il, A&&... a );
template<size_t I, class... A>
constexpr explicit variant( in_place_index_t<I>, A&&... a );
template<size_t I, class V, class... A>
constexpr explicit variant( in_place_index_t<I>,
std::initializer_list<V> il, A&&... a );
// destructor
~variant();
// assignment
constexpr variant& operator=( variant const & r ) noexcept( /*see below*/ );
constexpr variant& operator=( variant&& r ) noexcept( /*see below*/ );
template<class U> constexpr variant& operator=( U&& u ) noexcept( /*see below*/ );
// modifiers
template<class U, class... A>
constexpr U& emplace( A&&... a );
template<class U, class V, class... A>
constexpr U& emplace( std::initializer_list<V> il, A&&... a );
template<size_t I, class... A>
constexpr variant_alternative_t<I, variant<T...>>&
emplace( A&&... a );
template<size_t I, class V, class... A>
constexpr variant_alternative_t<I, variant<T...>>&
emplace( std::initializer_list<V> il, A&&... a );
// value status
constexpr bool valueless_by_exception() const noexcept;
constexpr size_t index() const noexcept;
// swap
void swap( variant& r ) noexcept( /*see below*/ );
// converting constructors (extension)
template<class... U> variant( variant<U...> const& r )
noexcept( /*see below*/ );
template<class... U> variant( variant<U...>&& r )
noexcept( /*see below*/ );
// subset (extension)
template<class... U> constexpr variant<U...> subset() & ;
template<class... U> constexpr variant<U...> subset() && ;
template<class... U> constexpr variant<U...> subset() const& ;
template<class... U> constexpr variant<U...> subset() const&& ;
};
} // namespace variant2
} // namespace boost
```
#### Constructors
```
constexpr variant() noexcept( std::is_nothrow_default_constructible_v<T0> );
```
[none]
* {blank}
+
Effects: :: Constructs a `variant` holding a value-initialized value of
type `T0`.
Ensures: :: `index() == 0`.
Throws: :: Any exception thrown by the value-initialization of `T0`.
Remarks: :: This function does not participate in overload resolution unless
`std::is_default_constructible_v<T0>` is `true`.
```
constexpr variant( variant const & w )
noexcept( mp_all<std::is_nothrow_copy_constructible<T>...>::value );
```
[none]
* {blank}
+
Effects: :: Initializes the variant to hold the same alternative and value as
`w`.
Throws: :: Any exception thrown by the initialization of the contained value.
Remarks: :: This function does not participate in overload resolution unless
`std::is_copy_constructible_v<Ti>` is `true` for all `i`.
```
constexpr variant( variant&& w )
noexcept( mp_all<std::is_nothrow_move_constructible<T>...>::value );
```
[none]
* {blank}
+
Effects: :: Initializes the variant to hold the same alternative and value as
`w`.
Throws: :: Any exception thrown by the move-initialization of the contained
value.
Remarks: :: This function does not participate in overload resolution unless
`std::is_move_constructible_v<Ti>` is `true` for all `i`.
```
template<class U> constexpr variant( U&& u ) noexcept(/*see below*/);
```
[none]
* {blank}
+
Let `Tj` be a type that is determined as follows: build an imaginary function
`FUN(Ti)` for each alternative type `Ti`. The overload `FUN(Tj)` selected by
overload resolution for the expression `FUN(std::forward<U>(u))` defines the
alternative `Tj` which is the type of the contained value after construction.
Effects: :: Initializes `*this` to hold the alternative type `Tj` and
initializes the contained value from `std::forward<U>(u)`.
Ensures: :: `holds_alternative<Tj>(*this)`.
Throws: :: Any exception thrown by the initialization of the contained value.
Remarks: :: The expression inside `noexcept` is equivalent to
`std::is_nothrow_constructible_v<Tj, U>`. This function does not participate in
overload resolution unless
- `sizeof...(T)` is nonzero,
- `std::is_same_v<std::remove_cvref_t<U>, variant>` is `false`,
- `std::remove_cvref_t<U>` is neither a specialization of `in_place_type_t` nor a
specialization of `in_place_index_t`,
- `std::is_constructible_v<Tj, U>` is `true`, and
- the expression `FUN(std::forward<U>(u))` is well-formed.
```
template<class U, class... A>
constexpr explicit variant( in_place_type_t<U>, A&&... a );
```
[none]
* {blank}
+
Effects: :: Initializes the contained value of type `U` with the arguments
`std::forward<A>(a)...`.
Ensures: :: `holds_alternative<U>(*this)`.
Throws: :: Any exception thrown by the initialization of the contained value.
Remarks: :: This function does not participate in overload resolution unless
there is exactly one occurrence of `U` in `T...` and
`std::is_constructible_v<U, A...>` is true.
```
template<class U, class V, class... A>
constexpr explicit variant( in_place_type_t<U>, std::initializer_list<V> il,
A&&... a );
```
[none]
* {blank}
+
Effects: :: Initializes the contained value of type `U` with the arguments `il`,
`std::forward<A>(a)...`.
Ensures: :: `holds_alternative<U>(*this)`.
Throws: :: Any exception thrown by the initialization of the contained value.
Remarks: :: This function does not participate in overload resolution unless
there is exactly one occurrence of `U` in `T...` and
`std::is_constructible_v<U, initializer_list<V>&, A...>` is `true`.
```
template<size_t I, class... A>
constexpr explicit variant( in_place_index_t<I>, A&&... a );
```
[none]
* {blank}
+
Effects: :: Initializes the contained value of type `TI` with the arguments
`std::forward<A>(a)...`.
Ensures: :: `index() == I`.
Throws: :: Any exception thrown by the initialization of the contained value.
Remarks: :: This function does not participate in overload resolution unless
`I < sizeof...(T)` and `std::is_constructible_v<TI, A...>` is `true`.
```
template<size_t I, class V, class... A>
constexpr explicit variant( in_place_index_t<I>, std::initializer_list<V> il,
A&&... a );
```
[none]
* {blank}
+
Effects: :: Initializes the contained value of type `TI` with the arguments
`il`, `std::forward<A>(a)...`.
Ensures: :: `index() == I`.
Throws: :: Any exception thrown by the initialization of the contained value.
Remarks: :: This function does not participate in overload resolution unless
`I < sizeof...(T)` and
`std::is_constructible_v<TI, initializer_list<V>&, A...>` is `true`.
#### Destructor
```
~variant();
```
[none]
* {blank}
+
Effects: :: Destroys the currently contained value.
#### Assignment
```
constexpr variant& operator=( const variant& r )
noexcept( mp_all<std::is_nothrow_copy_constructible<T>...,
std::is_nothrow_copy_assignable<T>...>::value );
```
[none]
* {blank}
+
Let `j` be `r.index()`.
Effects: ::
- If `index() == j`, assigns the value contained in `r` to the value
contained in `*this`.
- Otherwise, equivalent to `emplace<j>(get<j>(r))`.
Returns: :: `*this`.
Ensures: :: `index() == r.index()`.
Remarks: :: This operator does not participate in overload resolution unless
`std::is_copy_constructible_v<Ti> && std::is_copy_assignable_v<Ti>` is
`true` for all `i`.
```
constexpr variant& operator=( variant&& r )
noexcept( mp_all<std::is_nothrow_move_constructible<T>...,
std::is_nothrow_move_assignable<T>...>::value );
```
[none]
* {blank}
+
Let `j` be `r.index()`.
Effects: ::
- If `index() == j`, assigns the value contained in `std::move(r)` to the
value contained in `*this`.
- Otherwise, equivalent to `emplace<j>(get<j>(std::move(r)))`.
Returns: :: `*this`.
Ensures: :: `index() == r.index()`.
Remarks: :: This operator does not participate in overload resolution unless
`std::is_move_constructible_v<Ti> && std::is_move_assignable_v<Ti>` is
`true` for all `i`.
```
template<class U> constexpr variant& operator=( U&& u )
noexcept( /*see below*/ );
```
[none]
* {blank}
+
Let `Tj` be a type that is determined as follows: build an imaginary function
`FUN(Ti)` for each alternative type `Ti`. The overload `FUN(Tj)` selected by
overload resolution for the expression `FUN(std::forward<U>(u))` defines the
alternative `Tj` which is the type of the contained value after construction.
Effects: ::
- If `index() == j`, assigns `std::forward<U>(u)` to the value contained in
`*this`.
- Otherwise, equivalent to `emplace<j>(std::forward<U>(u))`.
Returns: :: `*this`.
Ensures: :: `index() == j`.
Remarks: ::
The expression inside `noexcept` is `std::is_nothrow_constructible_v<Tj, U>
&& std::is_nothrow_assignable_v<Tj&, U>`.
This operator does not participate in overload resolution unless
- `std::is_same_v<std::remove_cvref_t<T>, variant>` is `false`,
- `std::is_constructible_v<Tj, U> && std::is_assignable_v<Tj&, U>` is
`true`, and
- the expression `FUN(std::forward<U>(u))` (with `FUN` being the
above-mentioned set of imaginary functions) is well-formed.
#### Modifiers
```
template<class U, class... A>
constexpr U& emplace( A&&... a );
```
[none]
* {blank}
+
Let `I` be the zero-based index of `U` in `T...`.
Effects: :: Equivalent to: `return emplace<I>(std::forward<A>(a)...);`
Remarks: ::
This function shall not participate in overload resolution unless
`std::is_constructible_v<U, A...>` is `true` and `U` occurs exactly once
in `T...`.
```
template<class U, class V, class... A>
constexpr U& emplace( std::initializer_list<V> il, A&&... a );
```
[none]
* {blank}
+
Let `I` be the zero-based index of `U` in `T...`.
Effects: :: Equivalent to: `return emplace<I>(il, std::forward<A>(a)...);`
Remarks: ::
This function shall not participate in overload resolution unless
`std::is_constructible_v<U, std::initializer_list<V>&, A...>` is `true`
and `U` occurs exactly once in `T...`.
```
template<size_t I, class... A>
constexpr variant_alternative_t<I, variant<T...>>&
emplace( A&&... a );
```
[none]
* {blank}
+
Requires: :: `I < sizeof(T...)`.
Effects: ::
Destroys the currently contained value, then initializes a new contained
value as if using the expression `Ti(std::forward<A>(a)...)`.
Ensures: :: `index() == I`.
Returns: :: A reference to the new contained value.
Remarks: ::
This function shall not participate in overload resolution unless
`std::is_constructible_v<Ti, A...>` is `true`.
```
template<size_t I, class V, class... A>
constexpr variant_alternative_t<I, variant<T...>>&
emplace( std::initializer_list<V> il, A&&... a );
```
[none]
* {blank}
+
Requires: :: `I < sizeof(T...)`.
Effects: ::
Destroys the currently contained value, then initializes a new contained
value as if using the expression `Ti(il, std::forward<A>(a)...)`.
Ensures: :: `index() == I`.
Returns: :: A reference to the new contained value.
Remarks: ::
This function shall not participate in overload resolution unless
`std::is_constructible_v<Ti, std::initializer_list<V>&, A...>` is `true`.
#### Value Status
```
constexpr bool valueless_by_exception() const noexcept;
```
[none]
* {blank}
+
Returns: :: `false`.
```
constexpr size_t index() const noexcept;
```
[none]
* {blank}
+
Returns: :: The zero-based index of the active alternative.
#### Swap
```
void swap( variant& r ) noexcept( mp_all<std::is_nothrow_move_constructible<T>...,
is_nothrow_swappable<T>...>::value );
```
[none]
* {blank}
+
Effects: ::
- If `index() == r.index()`, calls `swap(get<I>(*this), get<I>(r))`,
where `I` is `index()`.
- Otherwise, as if
`variant tmp(std::move(*this)); *this = std::move(r); r = std::move(tmp);`
#### Converting Constructors (extension)
```
template<class... U> variant( variant<U...> const& r )
noexcept( mp_all<std::is_nothrow_copy_constructible<U>...>::value );
```
[none]
* {blank}
+
Effects: :: Initializes the contained value from the contained value of `r`.
Throws: :: Any exception thrown by the initialization of the contained value.
Remarks: :: This function does not participate in overload resolution unless
all types in `U...` are in `T...` and
`std::is_copy_constructible_v<Ui>::value` is `true` for all `Ui`.
```
template<class... U> variant( variant<U...>&& r )
noexcept( mp_all<std::is_nothrow_move_constructible<U>...>::value );
```
[none]
* {blank}
+
Effects: :: Initializes the contained value from the contained value of
`std::move(r)`.
Throws: :: Any exception thrown by the initialization of the contained value.
Remarks: :: This function does not participate in overload resolution unless
all types in `U...` are in `T...` and
`std::is_move_constructible_v<Ui>::value` is `true` for all `Ui`.
#### Subset (extension)
```
template<class... U> constexpr variant<U...> subset() & ;
```
```
template<class... U> constexpr variant<U...> subset() const& ;
```
[none]
* {blank}
+
Returns: :: A `variant<U...>` whose contained value is copy-initialized from
the contained value of `*this` and has the same type.
Throws: ::
- If the active alternative of `*this` is not among the types in `U...`,
`bad_variant_access`.
- Otherwise, any exception thrown by the initialization of the contained value.
Remarks: :: This function does not participate in overload resolution unless
all types in `U...` are in `T...` and
`std::is_copy_constructible_v<Ui>::value` is `true` for all `Ui`.
```
template<class... U> constexpr variant<U...> subset() && ;
```
```
template<class... U> constexpr variant<U...> subset() const&& ;
```
[none]
* {blank}
+
Returns: :: A `variant<U...>` whose contained value is move-initialized from
the contained value of `*this` and has the same type.
Throws: ::
- If the active alternative of `*this` is not among the types in `U...`,
`bad_variant_access`.
- Otherwise, any exception thrown by the initialization of the contained value.
Remarks: :: This function does not participate in overload resolution unless
all types in `U...` are in `T...` and
`std::is_move_constructible_v<Ui>::value` is `true` for all `Ui`.
### variant_alternative
```
template<size_t I, class T> struct variant_alternative<I, T const>;
```
```
template<size_t I, class T> struct variant_alternative<I, T volatile>;
```
```
template<size_t I, class T> struct variant_alternative<I, T const volatile>;
```
[none]
* {blank}
+
--
If `typename variant_alternative<I, T>::type` exists and is `U`,
* `variant_alternative<I, T const>::type` is `U const`;
* `variant_alternative<I, T volatile>::type` is `U volatile`;
* `variant_alternative<I, T const volatile>::type` is `U const volatile`.
Otherwise, the three structs have no `type` member.
--
```
template<size_t I, class... T>
struct variant_alternative<I, variant<T...>>;
```
[none]
* {blank}
+
When `I < sizeof...(T)`, the nested type `type` is an alias for the `I`-th
(zero-based) type in `T...`. Otherwise, there is no `type` member.
### holds_alternative
```
template<class U, class... T>
constexpr bool holds_alternative(const variant<T...>& v) noexcept;
```
[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...`.
### get
```
template<size_t I, class... T>
constexpr variant_alternative_t<I, variant<T...>>&
get(variant<T...>& v);
```
```
template<size_t I, class... T>
constexpr variant_alternative_t<I, variant<T...>>&&
get(variant<T...>&& v);
```
```
template<size_t I, class... T>
constexpr const variant_alternative_t<I, variant<T...>>&
get(const variant<T...>& v);
```
```
template<size_t I, class... T>
constexpr const variant_alternative_t<I, variant<T...>>&&
get(const variant<T...>&& v);
```
[none]
* {blank}
+
Effects: :: If `v.index()` is `I`, returns a reference to the object stored in
the variant. Otherwise, throws `bad_variant_access`.
```
template<class U, class... T>
constexpr U& get(variant<T...>& v);
```
```
template<class U, class... T>
constexpr U&& get(variant<T...>&& v);
```
```
template<class U, class... T>
constexpr const U& get(const variant<T...>& v);
```
```
template<class U, class... T>
constexpr const U&& get(const variant<T...>&& v);
```
[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`.
### get_if
```
template<size_t I, class... T>
constexpr add_pointer_t<variant_alternative_t<I, variant<T...>>>
get_if(variant<T...>* v) noexcept;
```
```
template<size_t I, class... T>
constexpr add_pointer_t<const variant_alternative_t<I, variant<T...>>>
get_if(const variant<T...>* v) noexcept;
```
```
template<class T, class... T>
constexpr add_pointer_t<T>
get_if(variant<T...>* v) noexcept;
```
```
template<class T, class... T>
constexpr add_pointer_t<const T>
get_if(const variant<T...>* v) noexcept;
```
[none]
* {blank}
+
Requires: :: `I < sizeof...(U)`. Otherwise, the program is ill-formed.
Effects: :: A pointer to the value stored in the variant, if
`v != nullptr && v\->index() == I`. Otherwise, `nullptr`.
### Relational Operators
```
template<class... T>
constexpr bool operator==(const variant<T...>& v, const variant<T...>& w);
```
[none]
* {blank}
+
Returns: :: `v.index() == w.index && get<I>(v) == get<I>(w)`, where `I`
is `v.index()`.
```
template<class... T>
constexpr bool operator!=(const variant<T...>& v, const variant<T...>& w);
```
[none]
* {blank}
+
Returns: :: `!(v == w)`.
```
template<class... T>
constexpr bool operator<(const variant<T...>& v, const variant<T...>& w);
```
[none]
* {blank}
+
Returns: :: `v.index() < w.index || (v.index() == w.index && get<I>(v) < get<I>(w))`,
where `I` is `v.index()`.
```
template<class... T>
constexpr bool operator>(const variant<T...>& v, const variant<T...>& w);
```
[none]
* {blank}
+
Returns: :: `w < v`.
```
template<class... T>
constexpr bool operator<=(const variant<T...>& v, const variant<T...>& w);
```
[none]
* {blank}
+
Returns: :: `v.index() < w.index || (v.index() == w.index && get<I>(v) \<= get<I>(w))`,
where `I` is `v.index()`.
```
template<class... T>
constexpr bool operator>=(const variant<T...>& v, const variant<T...>& w);
```
[none]
* {blank}
+
Returns: :: `w \<= v`.
### visit
```
template<class F, class... V>
constexpr /*see below*/ visit(F&& f, V&&... v);
```
[none]
* {blank}
+
Returns: :: `std::forward<F>(f)(get<I>(std::forward<V>(v))...)`, where
`I...` is `v.index()...`.
### swap
```
template<class... T>
void swap(variant<T...>& v, variant<T...>& w) noexcept( /*see below*/ );
```
[none]
* {blank}
+
Effects: :: Equivalent to `v.swap(w)`.
### bad_variant_access
```
class bad_variant_access: public std::exception
{
public:
bad_variant_access() noexcept = default;
char const * what() const noexcept
{
return "bad_variant_access";
}
};
```

File diff suppressed because it is too large Load Diff

View File

@@ -27,10 +27,10 @@ run variant_default_construct.cpp ;
compile variant_default_construct_cx.cpp ;
run variant_copy_construct.cpp ;
compile variant_copy_construct_cx.cpp ;
compile variant_copy_construct_cx.cpp : <toolset>msvc-14.0:<build>no ;
run variant_move_construct.cpp ;
compile variant_move_construct_cx.cpp ;
compile variant_move_construct_cx.cpp : [ requires cxx14_constexpr ] ;
run variant_value_construct.cpp ;
compile variant_value_construct_cx.cpp ;

View File

@@ -25,65 +25,130 @@ int main()
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<void> volatile>, void volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<void> const volatile>, void const volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char>&>, char&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char> const&>, char const&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char>&&>, char&&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char> const&&>, char const&&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<void, int>>, void>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<void, int> const>, void const>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<void, int> volatile>, void volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<void, int> const volatile>, void const volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char, int>&>, char&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char, int> const&>, char const&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char, int>&&>, char&&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char, int> const&&>, char const&&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int>>, int>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int> const>, int const>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int> volatile>, int volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int> const volatile>, int const volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int>&>, int&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int> const&>, int const&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int>&&>, int&&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int> const&&>, int const&&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<void, int, float>>, void>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<void, int, float> const>, void const>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<void, int, float> volatile>, void volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<void, int, float> const volatile>, void const volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char, int, float>&>, char&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char, int, float> const&>, char const&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char, int, float>&&>, char&&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<0, variant<char, int, float> const&&>, char const&&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int, float>>, int>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int, float> const>, int const>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int, float> volatile>, int volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int, float> const volatile>, int const volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int, float>&>, int&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int, float> const&>, int const&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int, float>&&>, int&&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<1, variant<void, int, float> const&&>, int const&&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<2, variant<void, int, float>>, float>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<2, variant<void, int, float> const>, float const>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<2, variant<void, int, float> volatile>, float volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<2, variant<void, int, float> const volatile>, float const volatile>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<2, variant<void, int, float>&>, float&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<2, variant<void, int, float> const&>, float const&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<2, variant<void, int, float>&&>, float&&>));
BOOST_TEST_TRAIT_TRUE((std::is_same<variant_alternative_t<2, variant<void, int, float> const&&>, float const&&>));
variant_alternative<0, void>();
variant_alternative<0, void const>();
variant_alternative<0, void volatile>();
variant_alternative<0, void const volatile>();
variant_alternative<0, int&>();
variant_alternative<0, int const&>();
variant_alternative<0, int&&>();
variant_alternative<0, int const&&>();
variant_alternative<0, variant<>>();
variant_alternative<0, variant<> const>();
variant_alternative<0, variant<> volatile>();
variant_alternative<0, variant<> const volatile>();
variant_alternative<0, variant<>&>();
variant_alternative<0, variant<> const&>();
variant_alternative<0, variant<>&&>();
variant_alternative<0, variant<> const&&>();
variant_alternative<1, variant<int>>();
variant_alternative<1, variant<int> const>();
variant_alternative<1, variant<int> volatile>();
variant_alternative<1, variant<int> const volatile>();
variant_alternative<1, variant<int>&>();
variant_alternative<1, variant<int> const&>();
variant_alternative<1, variant<int>&&>();
variant_alternative<1, variant<int> const&&>();
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, void const>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, void volatile>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, void const volatile>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, int&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, int const&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, int&&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, int const&&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, variant<>>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, variant<> const>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, variant<> volatile>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, variant<> const volatile>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, variant<>&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, variant<> const&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, variant<>&&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<0>, variant<> const&&>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_alt_t, mp_size_t<0>, variant<int>>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_alt_t, mp_size_t<0>, variant<int> const>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_alt_t, mp_size_t<0>, variant<int> volatile>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_alt_t, mp_size_t<0>, variant<int> const volatile>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_alt_t, mp_size_t<0>, variant<int>&>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_alt_t, mp_size_t<0>, variant<int> const&>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_alt_t, mp_size_t<0>, variant<int>&&>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_alt_t, mp_size_t<0>, variant<int> const&&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<1>, variant<int>>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<1>, variant<int> const>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<1>, variant<int> volatile>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<1>, variant<int> const volatile>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<1>, variant<int>&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<1>, variant<int> const&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<1>, variant<int>&&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_alt_t, mp_size_t<1>, variant<int> const&&>));
return boost::report_errors();
}

View File

@@ -6,13 +6,6 @@
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#if !defined( __cpp_constexpr ) || __cpp_constexpr < 201603
// no constexpr lambda support
int main() {}
#else
#include <boost/variant2/variant.hpp>
using namespace boost::variant2;
@@ -40,10 +33,9 @@ enum E
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
template<class T, class V> constexpr T test( V const& v )
template<class T, class V> constexpr T test( V const v )
{
V v2( v );
return get<T>(v);
return get<T>( v );
}
int main()
@@ -118,5 +110,3 @@ int main()
#endif
}
#endif // constexpr lambda support

View File

@@ -6,13 +6,6 @@
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#if !defined( __cpp_constexpr ) || __cpp_constexpr < 201603
// no constexpr lambda support
int main() {}
#else
#include <boost/variant2/variant.hpp>
#include <utility>
@@ -44,7 +37,7 @@ enum E
template<class T, class V> constexpr T test( V&& v )
{
V v2( std::forward<V>(v) );
return get<T>(v);
return get<T>( v2 );
}
int main()
@@ -109,5 +102,3 @@ int main()
#endif
}
#endif // constexpr lambda support

View File

@@ -25,40 +25,80 @@ int main()
BOOST_TEST_EQ( (variant_size<variant<> volatile>::value), 0 );
BOOST_TEST_EQ( (variant_size<variant<> const volatile>::value), 0 );
BOOST_TEST_EQ( (variant_size<variant<>&>::value), 0 );
BOOST_TEST_EQ( (variant_size<variant<> const&>::value), 0 );
BOOST_TEST_EQ( (variant_size<variant<>&&>::value), 0 );
BOOST_TEST_EQ( (variant_size<variant<> const&&>::value), 0 );
BOOST_TEST_EQ( (variant_size<variant<void>>::value), 1 );
BOOST_TEST_EQ( (variant_size<variant<void> const>::value), 1 );
BOOST_TEST_EQ( (variant_size<variant<void> volatile>::value), 1 );
BOOST_TEST_EQ( (variant_size<variant<void> const volatile>::value), 1 );
BOOST_TEST_EQ( (variant_size<variant<void>&>::value), 1 );
BOOST_TEST_EQ( (variant_size<variant<void> const&>::value), 1 );
BOOST_TEST_EQ( (variant_size<variant<void>&&>::value), 1 );
BOOST_TEST_EQ( (variant_size<variant<void> const&&>::value), 1 );
BOOST_TEST_EQ( (variant_size<variant<void, void>>::value), 2 );
BOOST_TEST_EQ( (variant_size<variant<void, void> const>::value), 2 );
BOOST_TEST_EQ( (variant_size<variant<void, void> volatile>::value), 2 );
BOOST_TEST_EQ( (variant_size<variant<void, void> const volatile>::value), 2 );
BOOST_TEST_EQ( (variant_size<variant<void, void>&>::value), 2 );
BOOST_TEST_EQ( (variant_size<variant<void, void> const&>::value), 2 );
BOOST_TEST_EQ( (variant_size<variant<void, void>&&>::value), 2 );
BOOST_TEST_EQ( (variant_size<variant<void, void> const&&>::value), 2 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void>>::value), 3 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void> const>::value), 3 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void> volatile>::value), 3 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void> const volatile>::value), 3 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void>&>::value), 3 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void> const&>::value), 3 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void>&&>::value), 3 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void> const&&>::value), 3 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void, void>>::value), 4 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void, void> const>::value), 4 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void, void> volatile>::value), 4 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void, void> const volatile>::value), 4 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void, void>&>::value), 4 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void, void> const&>::value), 4 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void, void>&&>::value), 4 );
BOOST_TEST_EQ( (variant_size<variant<void, void, void, void> const&&>::value), 4 );
variant_size<void>();
variant_size<void const>();
variant_size<void volatile>();
variant_size<void const volatile>();
variant_size<int&>();
variant_size<int const&>();
variant_size<int&&>();
variant_size<int const&&>();
BOOST_TEST_TRAIT_FALSE((mp_valid<var_size_t, void>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_size_t, void const>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_size_t, void volatile>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_size_t, void const volatile>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_size_t, int&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_size_t, int const&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_size_t, int&&>));
BOOST_TEST_TRAIT_FALSE((mp_valid<var_size_t, int const&&>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_size_t, variant<>>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_size_t, variant<> const>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_size_t, variant<> volatile>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_size_t, variant<> const volatile>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_size_t, variant<>&>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_size_t, variant<> const&>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_size_t, variant<>&&>));
BOOST_TEST_TRAIT_TRUE((mp_valid<var_size_t, variant<> const&&>));
return boost::report_errors();
}