diff options
Diffstat (limited to 'libs/variant')
21 files changed, 1992 insertions, 73 deletions
diff --git a/libs/variant/README.md b/libs/variant/README.md new file mode 100644 index 000000000..77cced9dc --- /dev/null +++ b/libs/variant/README.md @@ -0,0 +1,16 @@ +#[Boost.Variant](http://boost.org/libs/variant) +Boost.Variant, part of collection of the [Boost C++ Libraries](http://github.com/boostorg). It is a safe, generic, stack-based discriminated union container, offering a simple solution for manipulating an object from a heterogeneous set of types in a uniform manner. + +### Test results + +@ | Build | Tests coverage | More info +----------------|-------------- | -------------- |----------- +Develop branch: | [](https://travis-ci.org/apolukhin/variant) | [](https://coveralls.io/r/apolukhin/variant?branch=develop) | [details...](http://www.boost.org/development/tests/develop/developer/variant.html) +Master branch: | [](https://travis-ci.org/apolukhin/variant) | [](https://coveralls.io/r/apolukhin/variant?branch=master) | [details...](http://www.boost.org/development/tests/master/developer/variant.html) + + +[Open Issues](https://svn.boost.org/trac/boost/query?status=!closed&component=variant) + +### License + +Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt). diff --git a/libs/variant/doc/design.xml b/libs/variant/doc/design.xml index 857d39e36..756a6bdde 100644 --- a/libs/variant/doc/design.xml +++ b/libs/variant/doc/design.xml @@ -276,29 +276,6 @@ </para> - <para><emphasis role="bold">Caveat</emphasis>: On most platforms, the - <libraryname>Type Traits</libraryname> templates - <code>has_nothrow_copy</code> and <code>has_nothrow_constructor</code> - by default return <code>false</code> for all <code>class</code> and - <code>struct</code> types. It is necessary therefore to provide - specializations of these templates as appropriate for user-defined - types, as demonstrated in the following: - -<programlisting>// ...in your code (at file scope)... - -namespace boost { - - template <> - struct <classname>has_nothrow_copy</classname>< myUDT > - : <classname>mpl::true_</classname> - { - }; - -} -</programlisting> - - </para> - <para><emphasis role="bold">Implementation Note</emphasis>: So as to make the behavior of <code>variant</code> more predictable in the aftermath of an exception, the current implementation prefers to default-construct diff --git a/libs/variant/doc/reference/apply_visitor.xml b/libs/variant/doc/reference/apply_visitor.xml index b9a8798f0..bd1f10fe7 100644 --- a/libs/variant/doc/reference/apply_visitor.xml +++ b/libs/variant/doc/reference/apply_visitor.xml @@ -21,6 +21,9 @@ <simpara>See the "visitor-only" form of <code><functionname>apply_visitor</functionname></code> for a simple way to create <code>apply_visitor_delayed_t</code> objects.</simpara> + <simpara>See <code><classname>apply_visitor_delayed_cpp14_t</classname></code> + which is used on C++14 compatible compilers when <code>Visitor</code> has no + <code>result_type</code> typedef.</simpara> </description> <template> @@ -46,6 +49,18 @@ <overloaded-method name="operator()"> <signature> <template> + <template-type-parameter name="... Variant"/> + </template> + + <type>result_type</type> + <parameter name="operand"> + <paramtype>Variant&...</paramtype> + </parameter> + </signature> + + + <signature> + <template> <template-type-parameter name="Variant"/> </template> @@ -76,10 +91,69 @@ <code><functionname>apply_visitor</functionname></code> on the stored visitor using the given operands.</simpara> </description> + <notes>Version with variadic templates is used by default if + <macroname>BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES</macroname> is not defined.</notes> + </overloaded-method> + </method-group> + </class> + + <class name="apply_visitor_delayed_cpp14_t"> + <purpose>Adapts a visitor for use as a function object.</purpose> + <description> + <simpara>Adapts the function given at construction for use as a + function object. This is useful, for example, when one needs to + operate on each element of a sequence of variant objects using a + standard library algorithm such as + <code>std::for_each</code>.</simpara> + <simpara>See the "visitor-only" form of + <code><functionname>apply_visitor</functionname></code> for a simple + way to create <code>apply_visitor_delayed_t</code> objects.</simpara> + <simpara>See <code><classname>apply_visitor_delayed_t</classname></code> + which is used when <code>Visitor</code> has <code>result_type</code> + typedef.</simpara> + <simpara>Available only if macro + <macroname>BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES</macroname> is not defined and + compiler supports <code>decltype(auto)</code> and <code>decltype(some-expression)</code>.</simpara> + </description> + + <template> + <template-type-parameter name="Visitor"/> + </template> + + <constructor specifiers="explicit"> + <parameter name="visitor"> + <paramtype>Visitor &</paramtype> + </parameter> + + <effects> + <simpara>Constructs the function object with the given + visitor.</simpara> + </effects> + </constructor> + + <method-group name="function object interface"> + <overloaded-method name="operator()"> + <signature> + <template> + <template-type-parameter name="... Variant"/> + </template> + + <type>decltype(auto)</type> + <parameter name="operand"> + <paramtype>Variant&...</paramtype> + </parameter> + </signature> + + <purpose>Function call operator.</purpose> + <description> + <simpara>Invokes + <code><functionname>apply_visitor</functionname></code> on the + stored visitor using the given operands.</simpara> + </description> </overloaded-method> </method-group> </class> - + <overloaded-function name="apply_visitor"> <signature> <template> @@ -96,7 +170,7 @@ <paramtype>Variant &</paramtype> </parameter> </signature> - + <signature> <template> <template-type-parameter name="Visitor"/> @@ -120,7 +194,7 @@ <template-type-parameter name="Variant2"/> </template> - <type>typename BinaryVisitor::result_type</type> + <type>typename BinaryVisitor::result_type OR decltype(auto)</type> <parameter name="visitor"> <paramtype>BinaryVisitor &</paramtype> @@ -140,7 +214,7 @@ <template-type-parameter name="Variant2"/> </template> - <type>typename BinaryVisitor::result_type</type> + <type>typename BinaryVisitor::result_type OR decltype(auto)</type> <parameter name="visitor"> <paramtype>const BinaryVisitor &</paramtype> @@ -161,7 +235,7 @@ <template-type-parameter name="Variant3"/> </template> - <type>typename MultiVisitor::result_type</type> + <type>typename MultiVisitor::result_type OR decltype(auto)</type> <parameter name="visitor"> <paramtype>MultiVisitor &</paramtype> @@ -188,7 +262,7 @@ <template-type-parameter name="Variant3"/> </template> - <type>typename MultiVisitor::result_type</type> + <type>typename MultiVisitor::result_type OR decltype(auto)</type> <parameter name="visitor"> <paramtype>const MultiVisitor &</paramtype> @@ -219,6 +293,19 @@ </parameter> </signature> + + <signature> + <template> + <template-type-parameter name="Visitor"/> + </template> + + <type><classname>apply_visitor_delayed_cpp14_t</classname><Visitor></type> + + <parameter name="visitor"> + <paramtype>Visitor &</paramtype> + </parameter> + </signature> + <purpose> <simpara>Allows compile-time checked type-safe application of the given visitor to the content of the given variant, ensuring that all @@ -243,13 +330,17 @@ <listitem>Overloads accepting three or more operands invoke the function call operator of the given visitor on the content of the given <code><classname>variant</classname></code> - operands. Maximum amount of parameters controlled by + operands. Maximum amount of parameters controlled by <code><emphasis role="bold"><macroname>BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS</macroname></emphasis></code> - macro. Those functions are actually defined in <xref linkend="header.boost.variant.multivisitors_hpp"/>.</listitem> - - <listitem>The overload accepting only a visitor returns a - <classname alt="boost::apply_visitor_delayed_t">generic function object</classname> - that accepts either one or two arguments and invokes + macro. Those functions are actually defined in a header <code>boost/variant/multivisitors.hpp</code> + (See <xref linkend="header.boost.variant.multivisitors_hpp"/>). That header must be manually included + if multi visitors are meant for use.</listitem> + + <listitem>The overloads accepting only a visitor return a + <classname alt="boost::apply_visitor_delayed_t">C++03 compatible generic function object</classname> + or + <classname alt="boost::apply_visitor_delayed_cpp14_t">C++14 compatible generic function object</classname> + that accepts either one, two or arbitrary count of arguments and invoke <code><functionname>apply_visitor</functionname></code> using these arguments and <code>visitor</code>, thus behaving as specified above. (This behavior is particularly useful, for diff --git a/libs/variant/doc/reference/concepts.xml b/libs/variant/doc/reference/concepts.xml index 78c418e4a..03534ec2c 100644 --- a/libs/variant/doc/reference/concepts.xml +++ b/libs/variant/doc/reference/concepts.xml @@ -82,7 +82,9 @@ <listitem>Must allow invocation as a function by overloading <code>operator()</code>, unambiguously accepting any value of type <code>T</code>.</listitem> - <listitem>Must expose inner type <code>result_type</code>. (See + <listitem>Must expose inner type <code>result_type</code>. C++14 compatible compilers + could detect <code>result_type</code> automatically, but will stick to + <code>result_type</code> if it is defined. (See <code><functionname>boost::visitor_ptr</functionname></code> for a solution to using functions as visitors.)</listitem> <listitem>If <code>result_type</code> is not <code>void</code>, then @@ -131,6 +133,18 @@ public: } };</programlisting> + <para>C++14 compatible compilers detect <code>result_type</code> automatically:</para> + +<programlisting> + <classname>boost::variant</classname><int, float> v; + // ... + + <functionname>boost::apply_visitor</functionname>( + [](auto val) { return std::to_string(val); }, + v + ); +</programlisting> + </section> </section> diff --git a/libs/variant/doc/reference/get.xml b/libs/variant/doc/reference/get.xml index d8231bf56..ed30aa8de 100644 --- a/libs/variant/doc/reference/get.xml +++ b/libs/variant/doc/reference/get.xml @@ -26,7 +26,7 @@ </method> </class> - <overloaded-function name="get"> + <overloaded-function name="relaxed_get"> <signature> <template> <template-type-parameter name="U"/> @@ -58,7 +58,7 @@ <paramtype>const <classname>variant</classname><T1, T2, ..., TN> *</paramtype> </parameter> </signature> - + <signature> <template> <template-type-parameter name="U"/> @@ -93,7 +93,9 @@ <purpose> <simpara>Retrieves a value of a specified type from a given - <code><classname>variant</classname></code>.</simpara> + <code><classname>variant</classname></code>. </simpara> + <simpara>Unlike <functionname>strict_get</functionname> does not assert at compile time + that type <code>U</code> is one of the types that can be stored in variant.</simpara> </purpose> <description> @@ -102,6 +104,11 @@ <code><classname>variant</classname></code>. The function succeeds only if the content is of the specified type <code>U</code>, with failure indicated as described below.</simpara> + <simpara><emphasis role="bold">Recomendation</emphasis>: Use + <functionname>get</functionname> or <functionname>strict_get</functionname> in new code. + <functionname>strict_get</functionname> + provides more compile time checks and it's behavior is closer to <code>std::get</code> + from C++ Standard Library.</simpara> <simpara><emphasis role="bold">Warning</emphasis>: After either <code>operand</code> or its content is destroyed (e.g., when the given <code><classname>variant</classname></code> is assigned a @@ -148,5 +155,164 @@ </rationale> </overloaded-function> + <overloaded-function name="strict_get"> + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>U *</type> + + <parameter name="operand"> + <paramtype><classname>variant</classname><T1, T2, ..., TN> *</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>const U *</type> + + <parameter name="operand"> + <paramtype>const <classname>variant</classname><T1, T2, ..., TN> *</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>U &</type> + + <parameter name="operand"> + <paramtype><classname>variant</classname><T1, T2, ..., TN> &</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>const U &</type> + + <parameter name="operand"> + <paramtype>const <classname>variant</classname><T1, T2, ..., TN> &</paramtype> + </parameter> + </signature> + + <purpose> + <simpara>Retrieves a value of a specified type from a given + <code><classname>variant</classname></code>.</simpara> + </purpose> + + <description> + <simpara>Acts exactly like <functionname>relaxed_get</functionname> but does a compile time check + that type <code>U</code> is one of the types that can be stored in variant.</simpara> + </description> + </overloaded-function> + + <overloaded-function name="get"> + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>U *</type> + + <parameter name="operand"> + <paramtype><classname>variant</classname><T1, T2, ..., TN> *</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>const U *</type> + + <parameter name="operand"> + <paramtype>const <classname>variant</classname><T1, T2, ..., TN> *</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>U &</type> + + <parameter name="operand"> + <paramtype><classname>variant</classname><T1, T2, ..., TN> &</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>const U &</type> + + <parameter name="operand"> + <paramtype>const <classname>variant</classname><T1, T2, ..., TN> &</paramtype> + </parameter> + </signature> + + <purpose> + <simpara>Retrieves a value of a specified type from a given + <code><classname>variant</classname></code>.</simpara> + </purpose> + + <description> + <simpara>Evaluates to <functionname>strict_get</functionname> if <code>BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT</code> + is not defined. If <code>BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT</code> + is defined then evaluates to <functionname>relaxed_get</functionname>. </simpara> + + <simpara><emphasis role="bold">Recomendation</emphasis>: Use + <functionname>get</functionname> in new code without defining + <code>BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT</code>. In that way <functionname>get</functionname> + provides more compile time checks and it's behavior is closer to <code>std::get</code> + from C++ Standard Library.</simpara> + </description> + </overloaded-function> + </namespace> </header> diff --git a/libs/variant/doc/reference/multivisitor.xml b/libs/variant/doc/reference/multivisitor.xml index f9708d813..aef4a3bd1 100644 --- a/libs/variant/doc/reference/multivisitor.xml +++ b/libs/variant/doc/reference/multivisitor.xml @@ -16,7 +16,9 @@ <macro name="BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS"> <purpose> <simpara>Controls maximum amount of <code><classname>variant</classname></code> - parameters for multi visistors. </simpara> + parameters for multi visistors. Not used when <code>std::tuple</code> is available and + <code><macroname>BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES</macroname></code> + is not defined.</simpara> </purpose> <description> @@ -44,7 +46,7 @@ <template-type-parameter name="Variant3"/> </template> - <type>typename MultiVisitor::result_type</type> + <type>typename MultiVisitor::result_type OR decltype(auto)</type> <parameter name="visitor"> <paramtype>MultiVisitor &</paramtype> @@ -71,7 +73,7 @@ <template-type-parameter name="Variant3"/> </template> - <type>typename MultiVisitor::result_type</type> + <type>typename MultiVisitor::result_type OR decltype(auto)</type> <parameter name="visitor"> <paramtype>const MultiVisitor &</paramtype> diff --git a/libs/variant/doc/reference/polymorphic_get.xml b/libs/variant/doc/reference/polymorphic_get.xml index f6d85384c..aea0a7599 100644 --- a/libs/variant/doc/reference/polymorphic_get.xml +++ b/libs/variant/doc/reference/polymorphic_get.xml @@ -26,7 +26,7 @@ </method> </class> - <overloaded-function name="polymorphic_get"> + <overloaded-function name="polymorphic_relaxed_get"> <signature> <template> <template-type-parameter name="U"/> @@ -58,7 +58,7 @@ <paramtype>const <classname>variant</classname><T1, T2, ..., TN> *</paramtype> </parameter> </signature> - + <signature> <template> <template-type-parameter name="U"/> @@ -94,6 +94,8 @@ <purpose> <simpara>Retrieves a value of a specified type from a given <code><classname>variant</classname></code>.</simpara> + <simpara>Unlike <functionname>polymorphic_strict_get</functionname> does not assert at compile time + that type <code>U</code> is one of the types that can be stored in variant.</simpara> </purpose> <description> @@ -103,6 +105,12 @@ only if the content is of the specified type <code>U</code> or of type derived from type <code>U</code>, with failure indicated as described below.</simpara> + <simpara><emphasis role="bold">Recomendation</emphasis>: Use + <functionname>polymorphic_get</functionname> or <functionname>polymorphic_strict_get</functionname> + in new code. + <functionname>polymorphic_strict_get</functionname> + provides more compile time checks and it's behavior is closer to <code>std::get</code> + from C++ Standard Library.</simpara> <simpara><emphasis role="bold">Warning</emphasis>: After either <code>operand</code> or its content is destroyed (e.g., when the given <code><classname>variant</classname></code> is assigned a @@ -152,5 +160,167 @@ </rationale> </overloaded-function> + + + <overloaded-function name="polymorphic_strict_get"> + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>U *</type> + + <parameter name="operand"> + <paramtype><classname>variant</classname><T1, T2, ..., TN> *</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>const U *</type> + + <parameter name="operand"> + <paramtype>const <classname>variant</classname><T1, T2, ..., TN> *</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>U &</type> + + <parameter name="operand"> + <paramtype><classname>variant</classname><T1, T2, ..., TN> &</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>const U &</type> + + <parameter name="operand"> + <paramtype>const <classname>variant</classname><T1, T2, ..., TN> &</paramtype> + </parameter> + </signature> + + <purpose> + <simpara>Retrieves a value of a specified type from a given + <code><classname>variant</classname></code>.</simpara> + </purpose> + + <description> + <simpara>Acts exactly like <functionname>polymorphic_relaxed_get</functionname> but does a compile time check + that type <code>U</code> is one of the types that can be stored in variant.</simpara> + </description> + </overloaded-function> + + <overloaded-function name="polymorphic_get"> + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>U *</type> + + <parameter name="operand"> + <paramtype><classname>variant</classname><T1, T2, ..., TN> *</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>const U *</type> + + <parameter name="operand"> + <paramtype>const <classname>variant</classname><T1, T2, ..., TN> *</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>U &</type> + + <parameter name="operand"> + <paramtype><classname>variant</classname><T1, T2, ..., TN> &</paramtype> + </parameter> + </signature> + + <signature> + <template> + <template-type-parameter name="U"/> + <template-type-parameter name="T1"/> + <template-type-parameter name="T2"/> + <template-varargs/> + <template-type-parameter name="TN"/> + </template> + + <type>const U &</type> + + <parameter name="operand"> + <paramtype>const <classname>variant</classname><T1, T2, ..., TN> &</paramtype> + </parameter> + </signature> + + <purpose> + <simpara>Retrieves a value of a specified type from a given + <code><classname>variant</classname></code>.</simpara> + </purpose> + + <description> + <simpara>Evaluates to <functionname>polymorphic_strict_get</functionname> + if <code>BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT</code> + is not defined. If <code>BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT</code> + is defined then evaluates to <functionname>polymorphic_relaxed_get</functionname>. </simpara> + + <simpara><emphasis role="bold">Recomendation</emphasis>: Use + <functionname>polymorphic_get</functionname> in new code without defining + <code>BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT</code>. In that way + <functionname>polymorphic_get</functionname> + provides more compile time checks and it's behavior is closer to <code>std::get</code> + from C++ Standard Library.</simpara> + </description> + </overloaded-function> </namespace> </header> diff --git a/libs/variant/doc/reference/variant.xml b/libs/variant/doc/reference/variant.xml index 8c6cb8463..ba67fbeab 100644 --- a/libs/variant/doc/reference/variant.xml +++ b/libs/variant/doc/reference/variant.xml @@ -508,6 +508,12 @@ <method name="type" cv="const"> <type>const std::type_info &</type> + <notes> + <simpara><code>boost::variant</code> usues Boost.TypeIndex library so actually + <code>const boost::typeindex::type_info &</code> is returned. + This method is available even if RTTI is off.</simpara> + </notes> + <returns> <simpara><code>typeid(x)</code>, where <code>x</code> is the the content of <code>*this</code>.</simpara> @@ -515,10 +521,6 @@ <throws>Will not throw.</throws> - <notes> - <simpara>Not available when <code>BOOST_NO_TYPEID</code> is - defined.</simpara> - </notes> </method> </method-group> @@ -534,7 +536,7 @@ <paramtype>const variant &</paramtype> </parameter> </signature> - + <signature cv="const"> <type>void</type> <template> @@ -560,14 +562,60 @@ </requires> <returns> - <simpara><code>true</code> iff <code>which() == rhs.which()</code> + <simpara><code>true</code> if <code>which() == rhs.which()</code> <emphasis>and</emphasis> <code>content_this == content_rhs</code>, where <code>content_this</code> is the content of <code>*this</code> and <code>content_rhs</code> is the content of <code>rhs</code>.</simpara> </returns> - + + <throws> + <simpara>If <code>which() == rhs.which()</code> then may fail with + any exceptions arising from <code>operator==(T,T)</code>, where + <code>T</code> is the contained type of + <code>*this</code>.</simpara> + </throws> + </overloaded-method> + + <overloaded-method name="operator!=" cv="const"> + <purpose>InEquality comparison.</purpose> + + <signature cv="const"> + <type>bool</type> + <parameter name="rhs"> + <paramtype>const variant &</paramtype> + </parameter> + </signature> + + <signature cv="const"> + <type>void</type> + <template> + <template-type-parameter name="U"/> + </template> + <parameter> + <paramtype>const U &</paramtype> + </parameter> + </signature> + + <notes> + <simpara>The overload returning <code>void</code> exists only to + prohibit implicit conversion of the operator's right-hand side + to <code>variant</code>; thus, its use will (purposefully) + result in a compile-time error.</simpara> + </notes> + + <requires> + <simpara>Every bounded type of the <code>variant</code> must + fulfill the requirements of the + <conceptname>EqualityComparable</conceptname> + concept.</simpara> + </requires> + + <returns> + <simpara><code>true</code> if <code>!(*this == rhs)</code>.</simpara> + </returns> + <throws> <simpara>If <code>which() == rhs.which()</code> then may fail with any exceptions arising from <code>operator==(T,T)</code>, where @@ -585,7 +633,7 @@ <paramtype>const variant &</paramtype> </parameter> </signature> - + <signature cv="const"> <type>void</type> <template> @@ -626,6 +674,147 @@ </throws> </overloaded-method> + + <overloaded-method name="operator>"> + <purpose>GreaterThan comparison.</purpose> + + <signature cv="const"> + <type>bool</type> + <parameter name="rhs"> + <paramtype>const variant &</paramtype> + </parameter> + </signature> + + <signature cv="const"> + <type>void</type> + <template> + <template-type-parameter name="U"/> + </template> + <parameter> + <paramtype>const U &</paramtype> + </parameter> + </signature> + + <notes> + <simpara>The overload returning <code>void</code> exists only to + prohibit implicit conversion of the operator's right-hand side + to <code>variant</code>; thus, its use will (purposefully) + result in a compile-time error.</simpara> + </notes> + + <requires> + <simpara>Every bounded type of the <code>variant</code> must + fulfill the requirements of the + <conceptname>LessThanComparable</conceptname> + concept.</simpara> + </requires> + + <returns> + <simpara>true if <code>rhs < *this</code>.</simpara> + </returns> + + <throws> + <simpara>May fail with + any exceptions arising from <code>operator<(T,T)</code>, + where <code>T</code> is the contained type of + <code>*this</code>.</simpara> + </throws> + </overloaded-method> + + + <overloaded-method name="operator<="> + <purpose>LessThan or Equal comparison.</purpose> + + <signature cv="const"> + <type>bool</type> + <parameter name="rhs"> + <paramtype>const variant &</paramtype> + </parameter> + </signature> + + <signature cv="const"> + <type>void</type> + <template> + <template-type-parameter name="U"/> + </template> + <parameter> + <paramtype>const U &</paramtype> + </parameter> + </signature> + + <notes> + <simpara>The overload returning <code>void</code> exists only to + prohibit implicit conversion of the operator's right-hand side + to <code>variant</code>; thus, its use will (purposefully) + result in a compile-time error.</simpara> + </notes> + + <requires> + <simpara>Every bounded type of the <code>variant</code> must + fulfill the requirements of the + <conceptname>LessThanComparable</conceptname> + concept.</simpara> + </requires> + + <returns> + <simpara>true if <code>!(*this > rhs)</code>.</simpara> + </returns> + + <throws> + <simpara>May fail with + any exceptions arising from <code>operator<(T,T)</code>, + where <code>T</code> is the contained type of + <code>*this</code>.</simpara> + </throws> + </overloaded-method> + + + <overloaded-method name="operator>="> + <purpose>GreaterThan or Equal comparison.</purpose> + + <signature cv="const"> + <type>bool</type> + <parameter name="rhs"> + <paramtype>const variant &</paramtype> + </parameter> + </signature> + + <signature cv="const"> + <type>void</type> + <template> + <template-type-parameter name="U"/> + </template> + <parameter> + <paramtype>const U &</paramtype> + </parameter> + </signature> + + <notes> + <simpara>The overload returning <code>void</code> exists only to + prohibit implicit conversion of the operator's right-hand side + to <code>variant</code>; thus, its use will (purposefully) + result in a compile-time error.</simpara> + </notes> + + <requires> + <simpara>Every bounded type of the <code>variant</code> must + fulfill the requirements of the + <conceptname>LessThanComparable</conceptname> + concept.</simpara> + </requires> + + <returns> + <simpara>true if <code>!(*this < lhs)</code>.</simpara> + </returns> + + <throws> + <simpara>May fail with + any exceptions arising from <code>operator<(T,T)</code>, + where <code>T</code> is the contained type of + <code>*this</code>.</simpara> + </throws> + </overloaded-method> + </method-group> </class> diff --git a/libs/variant/doc/reference/variant_fwd.xml b/libs/variant/doc/reference/variant_fwd.xml index 60765ca9b..f94c75e48 100644 --- a/libs/variant/doc/reference/variant_fwd.xml +++ b/libs/variant/doc/reference/variant_fwd.xml @@ -42,7 +42,8 @@ Users may define this macro to make <code><macroname>BOOST_VARIANT_ENUM_PARAMS</macroname></code> and <code><macroname>BOOST_VARIANT_ENUM_SHIFTED_PARAMS</macroname></code> expand - to a comma-separated sequence instead of variadic templates. + to a comma-separated sequence instead of variadic templates. Define this macro if + your compiler has problems with compilation of variadic templates. </simpara> </purpose> </macro> diff --git a/libs/variant/doc/tutorial/advanced.xml b/libs/variant/doc/tutorial/advanced.xml index 6f63763f2..d4e8be738 100644 --- a/libs/variant/doc/tutorial/advanced.xml +++ b/libs/variant/doc/tutorial/advanced.xml @@ -397,19 +397,20 @@ struct if_visitor: public <classname>boost::static_visitor</classname><arithm arguments by means of <code>apply_visitor</code>: <programlisting> -bool_like_t v0(1), v1(true), v2(1.0); +bool_like_t v0(true), v1(1), v2(2.0); assert( <functionname>boost::apply_visitor</functionname>(if_visitor(), v0, v1, v2) == - arithmetics_t(true) + arithmetics_t(1) ); </programlisting> </para> <para>Finally, we must note that multi visitation does not support "delayed" form of - <code><functionname>apply_visitor</functionname></code>. + <code><functionname>apply_visitor</functionname> if + <macroname>BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES</macroname> is defined</code>. </para> </section> diff --git a/libs/variant/perf/move_perf.cpp b/libs/variant/perf/move_perf.cpp index efdd31d00..efdd31d00 100755..100644 --- a/libs/variant/perf/move_perf.cpp +++ b/libs/variant/perf/move_perf.cpp diff --git a/libs/variant/test/Jamfile.v2 b/libs/variant/test/Jamfile.v2 index 91b30595e..c861ac94f 100644 --- a/libs/variant/test/Jamfile.v2 +++ b/libs/variant/test/Jamfile.v2 @@ -28,10 +28,12 @@ test-suite variant [ run variant_reference_test.cpp ] [ run variant_comparison_test.cpp ] [ run variant_visit_test.cpp ] + [ run variant_get_test.cpp ] [ run variant_polymorphic_get_test.cpp ] [ run variant_multivisit_test.cpp ] [ run hash_variant_test.cpp ] [ run rvalue_test.cpp ] + [ run variant_nonempty_check.cpp ] [ run recursive_variant_test.cpp : : : <define>BOOST_NO_EXCEPTIONS <toolset>gcc-4.3:<cxxflags>-fno-exceptions <toolset>gcc-4.4:<cxxflags>-fno-exceptions @@ -44,6 +46,7 @@ test-suite variant ] [ run recursive_variant_test.cpp : : : <rtti>off <define>BOOST_NO_RTTI <define>BOOST_NO_TYPEID : variant_no_rtti_test ] [ run variant_swap_test.cpp ] + [ run auto_visitors.cpp ] ; diff --git a/libs/variant/test/auto_visitors.cpp b/libs/variant/test/auto_visitors.cpp new file mode 100644 index 000000000..84c91c9d2 --- /dev/null +++ b/libs/variant/test/auto_visitors.cpp @@ -0,0 +1,321 @@ +//----------------------------------------------------------------------------- +// boost-libs variant/test/auto_visitors.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2014-2015 Antony Polukhin +// +// 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 "boost/config.hpp" + +#include "boost/test/minimal.hpp" +#include "boost/variant.hpp" +#include "boost/variant/multivisitors.hpp" +#include "boost/lexical_cast.hpp" + +struct lex_streamer_explicit: boost::static_visitor<std::string> { + template <class T> + const char* operator()(const T& ) { + return "10"; + } + + template <class T1, class T2> + const char* operator()(const T1& , const T2& ) { + return "100"; + } +}; + + +void run_explicit() +{ + typedef boost::variant<int, std::string, double> variant_type; + variant_type v2("10"), v1("100"); + + lex_streamer_explicit visitor_ref; + + // Must return instance of std::string + BOOST_CHECK(boost::apply_visitor(visitor_ref, v2).c_str() == std::string("10")); + BOOST_CHECK(boost::apply_visitor(visitor_ref, v2, v1).c_str() == std::string("100")); +} + + +// Most part of tests from this file require decltype(auto) + +#ifdef BOOST_NO_CXX14_DECLTYPE_AUTO + +void run() +{ + BOOST_CHECK(true); +} + +void run2() +{ + BOOST_CHECK(true); +} + + +void run3() +{ + BOOST_CHECK(true); +} + +#else + +#include <iostream> + +struct lex_streamer { + template <class T> + std::string operator()(const T& val) const { + return boost::lexical_cast<std::string>(val); + } +}; + +struct lex_streamer_void { + template <class T> + void operator()(const T& val) const { + std::cout << val << std::endl; + } + + + template <class T1, class T2> + void operator()(const T1& val, const T2& val2) const { + std::cout << val << '+' << val2 << std::endl; + } + + + template <class T1, class T2, class T3> + void operator()(const T1& val, const T2& val2, const T3& val3) const { + std::cout << val << '+' << val2 << '+' << val3 << std::endl; + } +}; + + +struct lex_streamer2 { + std::string res; + + template <class T> + const char* operator()(const T& val) const { + return "fail"; + } + + template <class T1, class T2> + const char* operator()(const T1& v1, const T2& v2) const { + return "fail2"; + } + + + template <class T1, class T2, class T3> + const char* operator()(const T1& v1, const T2& v2, const T3& v3) const { + return "fail3"; + } + + template <class T> + std::string& operator()(const T& val) { + res = boost::lexical_cast<std::string>(val); + return res; + } + + + template <class T1, class T2> + std::string& operator()(const T1& v1, const T2& v2) { + res = boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2); + return res; + } + + + template <class T1, class T2, class T3> + std::string& operator()(const T1& v1, const T2& v2, const T3& v3) { + res = boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2) + + "+" + boost::lexical_cast<std::string>(v3); + return res; + } +}; + +#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES +# define BOOST_CHECK_IF_HAS_VARIADIC(x) BOOST_CHECK(x) +#else +# define BOOST_CHECK_IF_HAS_VARIADIC(x) /**/ +#endif + +void run() +{ + typedef boost::variant<int, std::string, double> variant_type; + variant_type v1(1), v2("10"), v3(100.0); + lex_streamer lex_streamer_visitor; + + BOOST_CHECK(boost::apply_visitor(lex_streamer(), v1) == "1"); + BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v1) == "1"); + BOOST_CHECK(boost::apply_visitor(lex_streamer(), v2) == "10"); + BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_streamer_visitor)(v2) == "10"); + + #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS + BOOST_CHECK(boost::apply_visitor([](auto v) { return boost::lexical_cast<std::string>(v); }, v1) == "1"); + BOOST_CHECK(boost::apply_visitor([](auto v) { return boost::lexical_cast<std::string>(v); }, v2) == "10"); + + // Retun type must be the same in all instances, so this code does not compile + //boost::variant<int, short, unsigned> v_diff_types(1); + //BOOST_CHECK(boost::apply_visitor([](auto v) { return v; }, v_diff_types) == 1); + + boost::apply_visitor([](auto v) { std::cout << v << std::endl; }, v1); + boost::apply_visitor([](auto v) { std::cout << v << std::endl; }, v2); + #endif + + lex_streamer2 visitor_ref; + BOOST_CHECK(boost::apply_visitor(visitor_ref, v1) == "1"); + BOOST_CHECK(boost::apply_visitor(visitor_ref, v2) == "10"); +#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES + std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1); + BOOST_CHECK(ref_to_string == "1"); +#endif + lex_streamer_void lex_streamer_void_visitor; + boost::apply_visitor(lex_streamer_void(), v1); + boost::apply_visitor(lex_streamer_void(), v2); +#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES + boost::apply_visitor(lex_streamer_void_visitor)(v2); +#endif +} + + +struct lex_combine { + template <class T1, class T2> + std::string operator()(const T1& v1, const T2& v2) const { + return boost::lexical_cast<std::string>(v1) + "+" + boost::lexical_cast<std::string>(v2); + } + + + template <class T1, class T2, class T3> + std::string operator()(const T1& v1, const T2& v2, const T3& v3) const { + return boost::lexical_cast<std::string>(v1) + "+" + + boost::lexical_cast<std::string>(v2) + '+' + + boost::lexical_cast<std::string>(v3); + } +}; + +void run2() +{ + typedef boost::variant<int, std::string, double> variant_type; + variant_type v1(1), v2("10"), v3(100.0); + lex_combine lex_combine_visitor; + + BOOST_CHECK(boost::apply_visitor(lex_combine(), v1, v2) == "1+10"); + BOOST_CHECK(boost::apply_visitor(lex_combine(), v2, v1) == "10+1"); + BOOST_CHECK_IF_HAS_VARIADIC(boost::apply_visitor(lex_combine_visitor)(v2, v1) == "10+1"); + + + #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS + BOOST_CHECK( + boost::apply_visitor( + [](auto v1, auto v2) { + return boost::lexical_cast<std::string>(v1) + "+" + + boost::lexical_cast<std::string>(v2); + } + , v1 + , v2 + ) == "1+10" + ); + BOOST_CHECK( + boost::apply_visitor( + [](auto v1, auto v2) { + return boost::lexical_cast<std::string>(v1) + "+" + + boost::lexical_cast<std::string>(v2); + } + , v2 + , v1 + ) == "10+1" + ); + + boost::apply_visitor([](auto v1, auto v2) { std::cout << v1 << '+' << v2 << std::endl; }, v1, v2); + boost::apply_visitor([](auto v1, auto v2) { std::cout << v1 << '+' << v2 << std::endl; }, v2, v1); + #endif + + + lex_streamer2 visitor_ref; + BOOST_CHECK(boost::apply_visitor(visitor_ref, v1, v2) == "1+10"); + BOOST_CHECK(boost::apply_visitor(visitor_ref, v2, v1) == "10+1"); +#ifndef BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES + std::string& ref_to_string = boost::apply_visitor(visitor_ref)(v1, v2); + BOOST_CHECK(ref_to_string == "1+10"); +#endif + + boost::apply_visitor(lex_streamer_void(), v1, v2); + boost::apply_visitor(lex_streamer_void(), v2, v1); +} + +#undef BOOST_CHECK_IF_HAS_VARIADIC + +void run3() +{ +#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + typedef boost::variant<int, std::string, double> variant_type; + variant_type v1(1), v2("10"), v3(100); + lex_combine lex_combine_visitor; + + BOOST_CHECK(boost::apply_visitor(lex_combine(), v1, v2, v3) == "1+10+100"); + BOOST_CHECK(boost::apply_visitor(lex_combine(), v2, v1, v3) == "10+1+100"); + BOOST_CHECK(boost::apply_visitor(lex_combine_visitor)(v2, v1, v3) == "10+1+100"); + + + #ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS + BOOST_CHECK( + boost::apply_visitor( + [](auto v1, auto v2, auto v3) { + return boost::lexical_cast<std::string>(v1) + "+" + + boost::lexical_cast<std::string>(v2) + "+" + + boost::lexical_cast<std::string>(v3); + } + , v1 + , v2 + , v3 + ) == "1+10+100" + ); + BOOST_CHECK( + boost::apply_visitor( + [](auto v1, auto v2, auto v3) { + return boost::lexical_cast<std::string>(v1) + "+" + + boost::lexical_cast<std::string>(v2) + "+" + + boost::lexical_cast<std::string>(v3); + } + , v3 + , v1 + , v3 + ) == "100+1+100" + ); + + boost::apply_visitor( + [](auto v1, auto v2, auto v3) { std::cout << v1 << '+' << v2 << '+' << v3 << std::endl; }, + v1, v2, v3 + ); + boost::apply_visitor( + [](auto v1, auto v2, auto v3) { std::cout << v1 << '+' << v2 << '+' << v3 << std::endl; }, + v2, v1, v3 + ); + #endif + + + lex_streamer2 visitor_ref; + BOOST_CHECK(boost::apply_visitor(visitor_ref, v1, v2) == "1+10"); + BOOST_CHECK(boost::apply_visitor(visitor_ref)(v2, v1) == "10+1"); + std::string& ref_to_string = boost::apply_visitor(visitor_ref, v1, v2); + BOOST_CHECK(ref_to_string == "1+10"); + + lex_streamer_void lex_streamer_void_visitor; + boost::apply_visitor(lex_streamer_void(), v1, v2, v1); + boost::apply_visitor(lex_streamer_void(), v2, v1, v1); + boost::apply_visitor(lex_streamer_void_visitor)(v2, v1, v1); +#endif // !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) +} +#endif + + +int test_main(int , char* []) +{ + run_explicit(); + run(); + run2(); + run3(); + + return 0; +} diff --git a/libs/variant/test/recursive_variant_test.cpp b/libs/variant/test/recursive_variant_test.cpp index 8b6434801..fc9eaf2a5 100644 --- a/libs/variant/test/recursive_variant_test.cpp +++ b/libs/variant/test/recursive_variant_test.cpp @@ -129,6 +129,43 @@ void test_recursive_variant() std::cout << "result1: " << result1 << '\n'; BOOST_CHECK(result1 == "( 3 5 ( 3 5 ) 7 ) "); + std::vector<var1_t> vec1_copy = vec1; + vec1_copy.erase(vec1_copy.begin() + 2); + vec1_copy.insert(vec1_copy.begin() + 2, vec1_copy); + var1 = vec1_copy; + result1 = printer()(var1); + std::cout << "result1+: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); + + // Uses move construction on compilers with rvalue references support + result1 = printer()( + var1_t( + std::vector<var1_t>(vec1_copy) + ) + ); + std::cout << "result1++: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); + + + var1_t vec1_another_copy(vec1_copy); + vec1_copy[2].swap(vec1_another_copy); + result1 = printer()( + var1_t(vec1_copy) + ); + std::cout << "result1+++1: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) "); + + result1 = printer()(vec1_another_copy); + std::cout << "result1++2: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 7 ) "); + + vec1_copy[2].swap(vec1_copy[2]); + result1 = printer()( + var1_t(vec1_copy) + ); + std::cout << "result1.2: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) "); + typedef boost::make_recursive_variant< boost::variant<int, double> , std::vector<boost::recursive_variant_> @@ -231,6 +268,36 @@ void test_recursive_variant_over() std::cout << "result1: " << result1 << '\n'; BOOST_CHECK(result1 == "( 3 5 ( 3 5 ) 7 ) "); + std::vector<var1_t> vec1_copy = vec1; + vec1_copy.erase(vec1_copy.begin() + 2); + vec1_copy.insert(vec1_copy.begin() + 2, vec1_copy); + var1 = vec1_copy; + result1 = printer()(var1); + std::cout << "result1+: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); + + // Uses move construction on compilers with rvalue references support + result1 = printer()( + var1_t( + std::vector<var1_t>(vec1_copy) + ) + ); + std::cout << "result1++: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 7 ) 7 ) "); + + + var1_t vec1_another_copy(vec1_copy); + vec1_copy[2].swap(vec1_another_copy); + result1 = printer()( + var1_t(vec1_copy) + ); + std::cout << "result1+++1: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 ( 3 5 ( 3 5 7 ) 7 ) 7 ) "); + + result1 = printer()(vec1_another_copy); + std::cout << "result1++2: " << result1 << '\n'; + BOOST_CHECK(result1 == "( 3 5 7 ) "); + typedef boost::make_recursive_variant_over< boost::mpl::vector< boost::make_variant_over<boost::mpl::vector<int, double> >::type diff --git a/libs/variant/test/rvalue_test.cpp b/libs/variant/test/rvalue_test.cpp index d2d849a55..8ef9d3971 100644 --- a/libs/variant/test/rvalue_test.cpp +++ b/libs/variant/test/rvalue_test.cpp @@ -16,8 +16,22 @@ #include "boost/type_traits/is_nothrow_move_assignable.hpp" #include "boost/mpl/bool.hpp" -// Most part of tests from this file require rvalue references support +#include <boost/blank.hpp> +#include <boost/swap.hpp> + +namespace swap_ambiguouty_test_ns { + struct A {}; + struct B {}; + + void swap_ambiguouty_test() { + // If boost::blank is not used, then it compiles. + typedef boost::variant<boost::blank, A, B> Variant; + Variant v1, v2; + swap(v1, v2); + } +} // namespace swap_ambiguouty_test_ns +// Most part of tests from this file require rvalue references support class move_copy_conting_class { public: @@ -288,6 +302,7 @@ void run_is_container_compilation_test() int test_main(int , char* []) { + swap_ambiguouty_test_ns::swap_ambiguouty_test(); run(); run1(); run_move_only(); diff --git a/libs/variant/test/test8.cpp b/libs/variant/test/test8.cpp index 0e64ba0d7..d228b4c6b 100644 --- a/libs/variant/test/test8.cpp +++ b/libs/variant/test/test8.cpp @@ -58,17 +58,17 @@ T& check_pass(Variant& v, T value) template <typename T, typename Variant> void check_fail(Variant& v) { - BOOST_CHECK(!get<T>(&v)); + BOOST_CHECK(!relaxed_get<T>(&v)); try { - T& r = get<T>(v); + T& r = relaxed_get<T>(v); (void)r; // suppress warning about r not being used BOOST_CHECK(false && &r); // should never reach } - catch(boost::bad_get&) + catch(const boost::bad_get& e) { - // (do nothing here) + BOOST_CHECK(!!e.what()); // make sure that what() is const qualified and returnes something } } diff --git a/libs/variant/test/variant_comparison_test.cpp b/libs/variant/test/variant_comparison_test.cpp index f04d2575c..3f6cc4176 100644 --- a/libs/variant/test/variant_comparison_test.cpp +++ b/libs/variant/test/variant_comparison_test.cpp @@ -3,8 +3,8 @@ // See http://www.boost.org for updates, documentation, and revision history. //----------------------------------------------------------------------------- // -// Copyright (c) 2003 -// Eric Friedman, Itay Maman +// Copyright (c) 2003 Eric Friedman, Itay Maman +// Copyright (c) 2014 Antony Polukhin // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -34,6 +34,9 @@ void assert_equality_comparable( BOOST_CHECK( !(&x == &y) || (x == y) ); BOOST_CHECK( !(&x == &z) || (x == z) ); BOOST_CHECK( !(&y == &z) || (y == z) ); + BOOST_CHECK( !(&x == &y) || !(x != y) ); + BOOST_CHECK( !(&x == &z) || !(x != z) ); + BOOST_CHECK( !(&y == &z) || !(y != z) ); // reflexivity check BOOST_CHECK( (x == x) ); @@ -43,12 +46,18 @@ void assert_equality_comparable( // symmetry check BOOST_CHECK( !(x == y) || (y == x) ); BOOST_CHECK( !(y == x) || (x == y) ); + BOOST_CHECK( (x != y) || (y == x) ); + BOOST_CHECK( (y != x) || (x == y) ); BOOST_CHECK( !(x == z) || (z == x) ); BOOST_CHECK( !(z == x) || (x == z) ); + BOOST_CHECK( (x != z) || (z == x) ); + BOOST_CHECK( (z != x) || (x == z) ); BOOST_CHECK( !(y == z) || (z == y) ); BOOST_CHECK( !(z == y) || (y == z) ); + BOOST_CHECK( (y != z) || (z == y) ); + BOOST_CHECK( (z != y) || (y == z) ); // transitivity check BOOST_CHECK( !(x == y && y == z) || (x == z) ); @@ -65,12 +74,34 @@ void assert_less_than_comparable( BOOST_CHECK( !(x < x) ); BOOST_CHECK( !(y < y) ); BOOST_CHECK( !(z < z) ); + BOOST_CHECK( !(x > x) ); + BOOST_CHECK( !(y > y) ); + BOOST_CHECK( !(z > z) ); + + BOOST_CHECK( (x <= x) ); + BOOST_CHECK( (y <= y) ); + BOOST_CHECK( (z <= z) ); + BOOST_CHECK( (x >= x) ); + BOOST_CHECK( (y >= y) ); + BOOST_CHECK( (z >= z) ); // transitivity check BOOST_CHECK( (x < y) ); BOOST_CHECK( (y < z) ); BOOST_CHECK( (x < z) ); + BOOST_CHECK( (x <= y) ); + BOOST_CHECK( (y <= z) ); + BOOST_CHECK( (x <= z) ); + + BOOST_CHECK( (z > y) ); + BOOST_CHECK( (y > x) ); + BOOST_CHECK( (z > x) ); + + BOOST_CHECK( (z >= y) ); + BOOST_CHECK( (y >= x) ); + BOOST_CHECK( (z >= x) ); + // antisymmetry check BOOST_CHECK( !(y < x) ); BOOST_CHECK( !(z < y) ); diff --git a/libs/variant/test/variant_get_test.cpp b/libs/variant/test/variant_get_test.cpp new file mode 100644 index 000000000..69b613729 --- /dev/null +++ b/libs/variant/test/variant_get_test.cpp @@ -0,0 +1,323 @@ +//----------------------------------------------------------------------------- +// boost-libs variant/test/variant_get_test.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2014 Antony Polukhin +// +// 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 "boost/variant/variant.hpp" +#include "boost/variant/get.hpp" +#include "boost/variant/polymorphic_get.hpp" +#include "boost/variant/recursive_wrapper.hpp" +#include "boost/test/minimal.hpp" + +struct base { + int trash; + + base() : trash(123) {} + base(const base& b) : trash(b.trash) { int i = 100; (void)i; } + const base& operator=(const base& b) { + trash = b.trash; + int i = 100; (void)i; + + return *this; + } + + virtual ~base(){} +}; + +struct derived1 : base{}; +struct derived2 : base{}; + +struct vbase { short trash; virtual ~vbase(){} virtual int foo() const { return 0; } }; +struct vderived1 : virtual vbase{ virtual int foo() const { return 1; } }; +struct vderived2 : virtual vbase{ virtual int foo() const { return 3; } }; +struct vderived3 : vderived1, vderived2 { virtual int foo() const { return 3; } }; + +typedef boost::variant<int, base, derived1, derived2, std::string> var_t; +typedef boost::variant<int, derived1, derived2, std::string> var_t_shortened; +typedef boost::variant<base, derived1, derived2> var_t_no_fallback; +typedef boost::variant<int&, base&, derived1&, derived2&, std::string&> var_ref_t; +typedef boost::variant<const int&, const base&, const derived1&, const derived2&, const std::string&> var_cref_t; + +struct recursive_structure; +typedef boost::variant< + int, base, derived1, derived2, std::string, boost::recursive_wrapper<recursive_structure> +> var_req_t; +struct recursive_structure { var_req_t var; }; + +template <class T, class V, class TestType> +inline void check_polymorphic_get_on_types_impl_single_type(V* v) +{ + if (!!boost::is_same<T, TestType>::value) { + BOOST_CHECK(boost::polymorphic_get<TestType>(v)); + BOOST_CHECK(boost::polymorphic_get<const TestType>(v)); + BOOST_CHECK(boost::polymorphic_strict_get<TestType>(v)); + BOOST_CHECK(boost::polymorphic_strict_get<const TestType>(v)); + BOOST_CHECK(boost::polymorphic_relaxed_get<TestType>(v)); + BOOST_CHECK(boost::polymorphic_relaxed_get<const TestType>(v)); + } else { + BOOST_CHECK(!boost::polymorphic_get<TestType>(v)); + BOOST_CHECK(!boost::polymorphic_get<const TestType>(v)); + BOOST_CHECK(!boost::polymorphic_strict_get<TestType>(v)); + BOOST_CHECK(!boost::polymorphic_strict_get<const TestType>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<TestType>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<const TestType>(v)); + } +} + +template <class T, class V, class TestType> +inline void check_get_on_types_impl_single_type(V* v) +{ + if (!!boost::is_same<T, TestType>::value) { + BOOST_CHECK(boost::get<TestType>(v)); + BOOST_CHECK(boost::get<const TestType>(v)); + BOOST_CHECK(boost::strict_get<TestType>(v)); + BOOST_CHECK(boost::strict_get<const TestType>(v)); + BOOST_CHECK(boost::relaxed_get<TestType>(v)); + BOOST_CHECK(boost::relaxed_get<const TestType>(v)); + } else { + BOOST_CHECK(!boost::get<TestType>(v)); + BOOST_CHECK(!boost::get<const TestType>(v)); + BOOST_CHECK(!boost::strict_get<TestType>(v)); + BOOST_CHECK(!boost::strict_get<const TestType>(v)); + BOOST_CHECK(!boost::relaxed_get<TestType>(v)); + BOOST_CHECK(!boost::relaxed_get<const TestType>(v)); + } +} + +template <class T, class V> +inline void check_get_on_types_impl(V* v) +{ + check_get_on_types_impl_single_type<T, V, int>(v); + check_polymorphic_get_on_types_impl_single_type<T, V, int>(v); + + check_get_on_types_impl_single_type<T, V, base>(v); + + check_get_on_types_impl_single_type<T, V, derived1>(v); + check_polymorphic_get_on_types_impl_single_type<T, V, derived1>(v); + + check_get_on_types_impl_single_type<T, V, derived2>(v); + check_polymorphic_get_on_types_impl_single_type<T, V, derived2>(v); + + check_get_on_types_impl_single_type<T, V, std::string>(v); + check_polymorphic_get_on_types_impl_single_type<T, V, std::string>(v); + + // Never exist in here + BOOST_CHECK(!boost::relaxed_get<short>(v)); + BOOST_CHECK(!boost::relaxed_get<const short>(v)); + BOOST_CHECK(!boost::relaxed_get<char>(v)); + BOOST_CHECK(!boost::relaxed_get<char*>(v)); + BOOST_CHECK(!boost::relaxed_get<bool>(v)); + BOOST_CHECK(!boost::relaxed_get<const bool>(v)); + + BOOST_CHECK(!boost::polymorphic_relaxed_get<short>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<const short>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<char>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<char*>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<bool>(v)); + BOOST_CHECK(!boost::polymorphic_relaxed_get<const bool>(v)); + + boost::get<T>(*v); // Must compile + boost::get<const T>(*v); // Must compile + boost::strict_get<T>(*v); // Must compile + boost::strict_get<const T>(*v); // Must compile + + boost::polymorphic_get<T>(*v); // Must compile + boost::polymorphic_get<const T>(*v); // Must compile + boost::polymorphic_strict_get<T>(*v); // Must compile + boost::polymorphic_strict_get<const T>(*v); // Must compile +} + +template <class T, class V> +inline void check_get_on_types(V* v) +{ + check_get_on_types_impl<T, V>(v); + check_get_on_types_impl<T, const V>(v); +} + +inline void get_test() +{ + var_t v; + check_get_on_types<int>(&v); + + var_t(base()).swap(v); + check_get_on_types<base>(&v); + + var_t(derived1()).swap(v); + check_get_on_types<derived1>(&v); + + var_t(derived2()).swap(v); + check_get_on_types<derived2>(&v); + + var_t(std::string("Hello")).swap(v); + check_get_on_types<std::string>(&v); + + var_t_shortened vs = derived2(); + check_polymorphic_get_on_types_impl_single_type<derived2, var_t_shortened, int>(&vs); + check_polymorphic_get_on_types_impl_single_type<derived2, const var_t_shortened, int>(&vs); + // Checking that Base is really determinated + check_polymorphic_get_on_types_impl_single_type<base, var_t_shortened, base>(&vs); + check_polymorphic_get_on_types_impl_single_type<base, const var_t_shortened, base>(&vs); + + vs = derived1(); + check_polymorphic_get_on_types_impl_single_type<derived2, var_t_shortened, int>(&vs); + check_polymorphic_get_on_types_impl_single_type<derived2, const var_t_shortened, int>(&vs); + // Checking that Base is really determinated + check_polymorphic_get_on_types_impl_single_type<base, var_t_shortened, base>(&vs); + check_polymorphic_get_on_types_impl_single_type<base, const var_t_shortened, base>(&vs); +} + +inline void get_test_no_fallback() +{ + var_t_no_fallback v; + var_t_no_fallback(base()).swap(v); + check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v); + check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v); + check_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v); + check_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v); + + var_t_no_fallback(derived1()).swap(v); + check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v); + check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v); + check_get_on_types_impl_single_type<derived1, var_t_no_fallback, derived1>(&v); + check_get_on_types_impl_single_type<derived1, const var_t_no_fallback, derived1>(&v); + + var_t_no_fallback(derived2()).swap(v); + check_polymorphic_get_on_types_impl_single_type<base, var_t_no_fallback, base>(&v); + check_polymorphic_get_on_types_impl_single_type<base, const var_t_no_fallback, base>(&v); + check_get_on_types_impl_single_type<derived2, var_t_no_fallback, derived2>(&v); + check_get_on_types_impl_single_type<derived2, const var_t_no_fallback, derived2>(&v); +} + +inline void get_ref_test() +{ + int i = 0; + var_ref_t v(i); + check_get_on_types<int>(&v); + + base b; + var_ref_t v1(b); + check_get_on_types<base>(&v1); + + derived1 d1; + var_ref_t v2(d1); + check_get_on_types<derived1>(&v2); + + derived2 d2; + var_ref_t v3(d2); + check_get_on_types<derived2>(&v3); + + std::string s("Hello"); + var_ref_t v4(s); + check_get_on_types<std::string>(&v4); +} + + +inline void get_cref_test() +{ + int i = 0; + var_cref_t v(i); + BOOST_CHECK(boost::get<const int>(&v)); + BOOST_CHECK(!boost::get<const base>(&v)); + + base b; + var_cref_t v1(b); + BOOST_CHECK(boost::get<const base>(&v1)); + BOOST_CHECK(!boost::get<const derived1>(&v1)); + BOOST_CHECK(!boost::get<const int>(&v1)); + + std::string s("Hello"); + const var_cref_t v4 = s; + BOOST_CHECK(boost::get<const std::string>(&v4)); + BOOST_CHECK(!boost::get<const int>(&v4)); +} + +inline void get_recursive_test() +{ + var_req_t v; + check_get_on_types<int>(&v); + + var_req_t(base()).swap(v); + check_get_on_types<base>(&v); + + var_req_t(derived1()).swap(v); + check_get_on_types<derived1>(&v); + + var_req_t(derived2()).swap(v); + check_get_on_types<derived2>(&v); + + var_req_t(std::string("Hello")).swap(v); + check_get_on_types<std::string>(&v); + + recursive_structure s = { v }; // copying "v" + v = s; + check_get_on_types<recursive_structure>(&v); +} + +template <class T> +inline void check_that_does_not_exist_impl() +{ + using namespace boost::detail::variant; + + BOOST_CHECK((holds_element<T, const int>::value)); + BOOST_CHECK((!holds_element<T, short>::value)); + BOOST_CHECK((!holds_element<T, short>::value)); + BOOST_CHECK((!holds_element<T, const short>::value)); + BOOST_CHECK((!holds_element<T, char*>::value)); + BOOST_CHECK((!holds_element<T, const char*>::value)); + BOOST_CHECK((!holds_element<T, char[5]>::value)); + BOOST_CHECK((!holds_element<T, const char[5]>::value)); + BOOST_CHECK((!holds_element<T, bool>::value)); + BOOST_CHECK((!holds_element<T, const bool>::value)); + + BOOST_CHECK((!holds_element<T, boost::recursive_wrapper<int> >::value)); + BOOST_CHECK((!holds_element<T, boost::recursive_wrapper<short> >::value)); + BOOST_CHECK((!holds_element<T, boost::detail::reference_content<short> >::value)); + + + BOOST_CHECK((holds_element_polymorphic<T, const int>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, short>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, short>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, const short>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, char*>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, const char*>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, char[5]>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, const char[5]>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, bool>::value)); + BOOST_CHECK((!holds_element_polymorphic<T, const bool>::value)); + + BOOST_CHECK((!holds_element_polymorphic<T, boost::recursive_wrapper<int> >::value)); + BOOST_CHECK((!holds_element_polymorphic<T, boost::recursive_wrapper<short> >::value)); + BOOST_CHECK((!holds_element_polymorphic<T, boost::detail::reference_content<short> >::value)); +} + +inline void check_that_does_not_exist() +{ + using namespace boost::detail::variant; + + BOOST_CHECK((holds_element<var_t, int>::value)); + BOOST_CHECK((holds_element<var_ref_t, int>::value)); + BOOST_CHECK((!holds_element<var_cref_t, int>::value)); + + check_that_does_not_exist_impl<var_t>(); + check_that_does_not_exist_impl<var_ref_t>(); + check_that_does_not_exist_impl<var_cref_t>(); + check_that_does_not_exist_impl<var_req_t>(); +} + +int test_main(int , char* []) +{ + get_test(); + get_test_no_fallback(); + get_ref_test(); + get_cref_test(); + get_recursive_test(); + check_that_does_not_exist(); + + return boost::exit_success; +} diff --git a/libs/variant/test/variant_multivisit_test.cpp b/libs/variant/test/variant_multivisit_test.cpp index ddcbe02da..8fc3ebe82 100644 --- a/libs/variant/test/variant_multivisit_test.cpp +++ b/libs/variant/test/variant_multivisit_test.cpp @@ -3,37 +3,46 @@ // See http://www.boost.org for updates, documentation, and revision history. //----------------------------------------------------------------------------- // -// Copyright (c) 2013 -// Antony Polukhin +// Copyright (c) 2013-2015 Antony Polukhin // // 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 "boost/config.hpp" +#include "boost/noncopyable.hpp" #define BOOST_VARAINT_MAX_MULTIVIZITOR_PARAMS 5 #include "boost/variant/multivisitors.hpp" +#include "boost/variant.hpp" #include "boost/test/minimal.hpp" +struct my_noncopyable : boost::noncopyable { + my_noncopyable(){} + ~my_noncopyable(){} +}; + +typedef boost::variant<my_noncopyable, int> variant_noncopy_t; + + typedef boost::variant<char, unsigned char, signed char, unsigned short, int, unsigned int> variant6_t; struct test_visitor: boost::static_visitor<> { // operators that shall not be called template <class T1, class T2, class T3> - void operator()(T1, T2, T3) const + void operator()(T1&, T2&, T3&) const { BOOST_CHECK(false); } template <class T1, class T2, class T3, class T4> - void operator()(T1, T2, T3, T4) const + void operator()(T1&, T2&, T3&, T4&) const { BOOST_CHECK(false); } template <class T1, class T2, class T3, class T4, class T5> - void operator()(T1, T2, T3, T4, T5) const + void operator()(T1&, T2&, T3&, T4&, T5&) const { BOOST_CHECK(false); } @@ -62,6 +71,21 @@ struct test_visitor: boost::static_visitor<> { BOOST_CHECK(v3 == 3); BOOST_CHECK(v4 == 4); } + + + // Noncopyables + void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&) const { + BOOST_CHECK(true); + } + void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&) const { + BOOST_CHECK(true); + } + void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&) const { + BOOST_CHECK(true); + } + void operator()(my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&, my_noncopyable&) const { + BOOST_CHECK(true); + } }; typedef boost::variant<int, double, bool> bool_like_t; @@ -112,13 +136,24 @@ int test_main(int , char* []) arithmetics_t(true) ); - /* Delayed multi visitation is not implemented +#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) if_visitor if_vis; BOOST_CHECK( boost::apply_visitor(if_vis)(v0, v1, v2) == arithmetics_t(true) ); - */ +#endif + + + variant_noncopy_t vnonc[6]; + boost::apply_visitor(v, vnonc[0], vnonc[1], vnonc[2]); + boost::apply_visitor(test_visitor(), vnonc[0], vnonc[1], vnonc[2], vnonc[3]); + +#ifdef BOOST_VARIANT_MULTIVISITORS_TEST_VERY_EXTREME + boost::apply_visitor(v, vnonc[0], vnonc[1], vnonc[2], vnonc[3], vnonc[4]); + boost::apply_visitor(test_visitor(), vnonc[0], vnonc[1], vnonc[2], vnonc[3], vnonc[4], vnonc[5]); +#endif + return boost::exit_success; } diff --git a/libs/variant/test/variant_nonempty_check.cpp b/libs/variant/test/variant_nonempty_check.cpp new file mode 100644 index 000000000..de643b862 --- /dev/null +++ b/libs/variant/test/variant_nonempty_check.cpp @@ -0,0 +1,474 @@ +//----------------------------------------------------------------------------- +// boost-libs variant/test/variant_nonempty_check.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2014 Antony Polukhin +// +// 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) + + +// In this file we are making tests to ensure that variant guarantees nonemptiness. +// +// For that purpose we create a `throwing_class`, that throws exception at a specified +// assignment attempt. If exception was thrown during move/assignemnt operation we make sure +// that data in variant is same as before move/assignemnt operation or that a fallback type is +// stored in variant. +// +// Different nonthrowing_class'es are used to tests different variant internal policies: +// with/without fallback type + throw/nothrow copyable + throw/nothrow movable + + +#include "boost/variant/variant.hpp" +#include "boost/variant/get.hpp" +#include "boost/test/minimal.hpp" +#include <stdexcept> + +struct exception_on_assignment : std::exception {}; +struct exception_on_move_assignment : exception_on_assignment {}; + +void prevent_compiler_noexcept_detection() { + char* p = new char; + *p = '\0'; + delete p; +} + + +struct throwing_class { + int trash; + enum helper_enum { + do_not_throw = 780, + throw_after_5, + throw_after_4, + throw_after_3, + throw_after_2, + throw_after_1 + }; + + bool is_throw() { + if (trash < do_not_throw) { + return true; + } + + if (trash > do_not_throw && trash <= throw_after_1) { + ++ trash; + return false; + } + + return trash != do_not_throw; + } + + throwing_class(int value = 123) BOOST_NOEXCEPT_IF(false) : trash(value) { + prevent_compiler_noexcept_detection(); + } + + throwing_class(const throwing_class& b) BOOST_NOEXCEPT_IF(false) : trash(b.trash) { + if (is_throw()) { + throw exception_on_assignment(); + } + } + + const throwing_class& operator=(const throwing_class& b) BOOST_NOEXCEPT_IF(false) { + trash = b.trash; + if (is_throw()) { + throw exception_on_assignment(); + } + + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + throwing_class(throwing_class&& b) BOOST_NOEXCEPT_IF(false) : trash(b.trash) { + if (is_throw()) { + throw exception_on_move_assignment(); + } + } + + const throwing_class& operator=(throwing_class&& b) BOOST_NOEXCEPT_IF(false) { + trash = b.trash; + if (is_throw()) { + throw exception_on_move_assignment(); + } + + return *this; + } +#endif + + virtual ~throwing_class() {} +}; + +struct nonthrowing_class { + int trash; + + nonthrowing_class() BOOST_NOEXCEPT_IF(false) : trash(123) { + prevent_compiler_noexcept_detection(); + } + + nonthrowing_class(const nonthrowing_class&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + } + + const nonthrowing_class& operator=(const nonthrowing_class&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + nonthrowing_class(nonthrowing_class&&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + } + + const nonthrowing_class& operator=(nonthrowing_class&&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + return *this; + } +#endif +}; + +struct nonthrowing_class2 { + int trash; + + nonthrowing_class2() BOOST_NOEXCEPT_IF(false) : trash(123) { + prevent_compiler_noexcept_detection(); + } +}; + +struct nonthrowing_class3 { + int trash; + + nonthrowing_class3() BOOST_NOEXCEPT_IF(true) : trash(123) {} + + nonthrowing_class3(const nonthrowing_class3&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + } + + const nonthrowing_class3& operator=(const nonthrowing_class3&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + nonthrowing_class3(nonthrowing_class3&&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + } + + const nonthrowing_class3& operator=(nonthrowing_class3&&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + return *this; + } +#endif +}; + +struct nonthrowing_class4 { + int trash; + + nonthrowing_class4() BOOST_NOEXCEPT_IF(false) : trash(123) { + prevent_compiler_noexcept_detection(); + } + + nonthrowing_class4(const nonthrowing_class4&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + } + + const nonthrowing_class4& operator=(const nonthrowing_class4&) BOOST_NOEXCEPT_IF(false) { + prevent_compiler_noexcept_detection(); + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + nonthrowing_class4(nonthrowing_class4&&) BOOST_NOEXCEPT_IF(true) { + } + + const nonthrowing_class4& operator=(nonthrowing_class4&&) BOOST_NOEXCEPT_IF(true) { + return *this; + } +#endif +}; + + +// Tests ///////////////////////////////////////////////////////////////////////////////////// + + +template <class Nonthrowing> +inline void check_1_impl(int helper) +{ + boost::variant<throwing_class, Nonthrowing> v; + try { + v = throwing_class(helper); + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } + + try { + throwing_class tc(helper); + v = tc; + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } +} + +inline void check_1(int helper = 1) +{ + check_1_impl<nonthrowing_class>(helper); + check_1_impl<nonthrowing_class2>(helper); + check_1_impl<nonthrowing_class3>(helper); + check_1_impl<nonthrowing_class4>(helper); + check_1_impl<boost::blank>(helper); +} + +template <class Nonthrowing> +inline void check_2_impl(int helper) +{ + boost::variant<Nonthrowing, throwing_class> v; + try { + v = throwing_class(helper); + BOOST_CHECK(v.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v)); + } + + try { + throwing_class cl(helper); + v = cl; + BOOST_CHECK(v.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v)); + } +} + +inline void check_2(int helper = 1) +{ + check_2_impl<nonthrowing_class>(helper); + check_2_impl<nonthrowing_class2>(helper); + check_2_impl<nonthrowing_class3>(helper); + check_2_impl<nonthrowing_class4>(helper); + check_2_impl<boost::blank>(helper); +} + +template <class Nonthrowing> +inline void check_3_impl(int helper) +{ + boost::variant<Nonthrowing, throwing_class> v1, v2; + + swap(v1, v2); + try { + v1 = throwing_class(helper); + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v1.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v1)); + } + + + try { + v2 = throwing_class(helper); + BOOST_CHECK(v2.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v2)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v2.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v2)); + } + + + if (!v1.which() && !v2.which()) { + swap(v1, v2); // Make sure that two backup holders swap well + BOOST_CHECK(!v1.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v1)); + BOOST_CHECK(!v2.which()); + BOOST_CHECK(boost::get<Nonthrowing>(&v2)); + + v1 = v2; + } +} + +inline void check_3(int helper = 1) +{ + check_3_impl<nonthrowing_class>(helper); + check_3_impl<nonthrowing_class2>(helper); + check_3_impl<nonthrowing_class3>(helper); + check_3_impl<nonthrowing_class4>(helper); + check_3_impl<boost::blank>(helper); +} + +inline void check_4(int helper = 1) +{ + // This one has a fallback + boost::variant<int, throwing_class> v1, v2; + + swap(v1, v2); + try { + v1 = throwing_class(helper); + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v1.which()); + BOOST_CHECK(boost::get<int>(&v1)); + } + + + try { + v2 = throwing_class(helper); + BOOST_CHECK(v2.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v2)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(!v2.which()); + BOOST_CHECK(boost::get<int>(&v2)); + } + + if (!v1.which() && !v2.which()) { + swap(v1, v2); + BOOST_CHECK(!v1.which()); + BOOST_CHECK(boost::get<int>(&v1)); + BOOST_CHECK(!v2.which()); + BOOST_CHECK(boost::get<int>(&v2)); + + v1 = v2; + } +} + +template <class Nonthrowing> +inline void check_5_impl(int helper) +{ + boost::variant<Nonthrowing, throwing_class> v1, v2; + throwing_class throw_not_now; + throw_not_now.trash = throwing_class::do_not_throw; + v1 = throw_not_now; + v2 = throw_not_now; + + boost::get<throwing_class>(v1).trash = 1; + boost::get<throwing_class>(v2).trash = 1; + + try { + v1 = throwing_class(helper); + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } + + boost::get<throwing_class>(v1).trash = throwing_class::do_not_throw; + boost::get<throwing_class>(v2).trash = throwing_class::do_not_throw; + v1 = Nonthrowing(); + v2 = Nonthrowing(); + try { + v1 = throwing_class(helper); + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v1.which() == 0); + BOOST_CHECK(boost::get<Nonthrowing>(&v1)); + } + + int v1_type = v1.which(); + int v2_type = v2.which(); + try { + swap(v1, v2); // Make sure that backup holders swap well + BOOST_CHECK(v1.which() == v2_type); + BOOST_CHECK(v2.which() == v1_type); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v1.which() == v1_type); + BOOST_CHECK(v2.which() == v2_type); + } +} + + +inline void check_5(int helper = 1) +{ + check_5_impl<nonthrowing_class>(helper); + check_5_impl<nonthrowing_class2>(helper); + check_5_impl<nonthrowing_class3>(helper); + check_5_impl<nonthrowing_class4>(helper); + check_5_impl<boost::blank>(helper); +} + +template <class Nonthrowing> +inline void check_6_impl(int helper) +{ + boost::variant<Nonthrowing, throwing_class> v1, v2; + throwing_class throw_not_now; + throw_not_now.trash = throwing_class::do_not_throw; + v1 = throw_not_now; + v2 = throw_not_now; + + v1 = throw_not_now; + v2 = throw_not_now; + swap(v1, v2); + boost::get<throwing_class>(v1).trash = 1; + boost::get<throwing_class>(v2).trash = 1; + + v1 = throwing_class(throw_not_now); + v2 = v1; + + v1 = Nonthrowing(); + try { + throwing_class tc; + tc.trash = helper; + v1 = tc; + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(boost::get<throwing_class>(&v1)); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v1.which() == 0); + } + + v2 = Nonthrowing(); + try { + v2 = 2; + BOOST_CHECK(false); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v2.which() == 0); + } + + // Probably the most significant test: + // unsuccessful swap must preserve old values of vaiant + v1 = throw_not_now; + boost::get<throwing_class>(v1).trash = helper; + try { + swap(v1, v2); + } catch (const exception_on_assignment& /*e*/) { + BOOST_CHECK(v1.which() == 1); + BOOST_CHECK(v2.which() == 0); + BOOST_CHECK(boost::get<throwing_class>(v1).trash == helper); + } +} + + +inline void check_6(int helper = 1) +{ + check_6_impl<nonthrowing_class>(helper); + check_6_impl<nonthrowing_class2>(helper); + check_6_impl<nonthrowing_class3>(helper); + check_6_impl<nonthrowing_class4>(helper); + check_6_impl<boost::blank>(helper); +} + +int test_main(int , char* []) +{ + // throwing_class::throw_after_1 + 1 => throw on first assignment/construction + // throwing_class::throw_after_1 => throw on second assignment/construction + // throwing_class::throw_after_2 => throw on third assignment/construction + // ... + for (int i = throwing_class::throw_after_1 + 1; i != throwing_class::do_not_throw; --i) { + check_1(i); + check_2(i); + check_3(i); + check_4(i); + check_5(i); + check_6(i); + } + + return boost::exit_success; +} diff --git a/libs/variant/test/variant_polymorphic_get_test.cpp b/libs/variant/test/variant_polymorphic_get_test.cpp index d4e6fe4a9..43fc7b6b9 100644 --- a/libs/variant/test/variant_polymorphic_get_test.cpp +++ b/libs/variant/test/variant_polymorphic_get_test.cpp @@ -1,10 +1,10 @@ //----------------------------------------------------------------------------- -// boost-libs variant/test/variant_visit_test.cpp source file +// boost-libs variant/test/variant_plymorphic_get_test.cpp source file // See http://www.boost.org for updates, documentation, and revision history. //----------------------------------------------------------------------------- // -// Copyright (c) 2003 -// Eric Friedman +// Copyright (c) 2003 Eric Friedman +// Copyright (c) 2013-2014 Antony Polukhin // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -25,24 +25,44 @@ struct vderived1 : virtual vbase{ virtual int foo() const { return 1; } }; struct vderived2 : virtual vbase{ virtual int foo() const { return 3; } }; struct vderived3 : vderived1, vderived2 { virtual int foo() const { return 3; } }; +template <class T, class Variant> +inline void check_throws(Variant& v) { + try { + boost::polymorphic_get<T>(v); + BOOST_CHECK(false); + } catch (const boost::bad_polymorphic_get& e) { + BOOST_CHECK(!!e.what()); + BOOST_CHECK(std::string(e.what()) != boost::bad_get().what()); + } +} + int test_main(int , char* []) { typedef boost::variant<int, base, derived1, derived2> var_t; var_t var1; BOOST_CHECK(!boost::polymorphic_get<base>(&var1)); + check_throws<base>(var1); + BOOST_CHECK(!boost::polymorphic_get<const base>(&var1)); + check_throws<base, const var_t>(var1); var1 = derived1(); BOOST_CHECK(boost::polymorphic_get<base>(&var1)); + BOOST_CHECK(boost::polymorphic_get<const base>(&var1)); derived2 d; d.trash = 777; var_t var2 = d; BOOST_CHECK(boost::polymorphic_get<base>(var2).trash == 777); + BOOST_CHECK(boost::polymorphic_get<const base>(var2).trash == 777); var2 = 777; BOOST_CHECK(!boost::polymorphic_get<base>(&var2)); + check_throws<base>(var2); + BOOST_CHECK(!boost::polymorphic_get<const base>(&var2)); + check_throws<base, const var_t>(var2); BOOST_CHECK(boost::polymorphic_get<int>(var2) == 777); + BOOST_CHECK(boost::polymorphic_get<const int>(var2) == 777); typedef boost::variant<int, vbase, vderived1, vderived2, vderived3> vvar_t; @@ -50,9 +70,12 @@ int test_main(int , char* []) boost::polymorphic_get<vderived3>(v).trash = 777; const vvar_t& cv = v; BOOST_CHECK(boost::polymorphic_get<vbase>(cv).trash == 777); + BOOST_CHECK(boost::polymorphic_get<const vbase>(cv).trash == 777); BOOST_CHECK(boost::polymorphic_get<vbase>(cv).foo() == 3); BOOST_CHECK(boost::polymorphic_get<vbase>(v).foo() == 3); + BOOST_CHECK(boost::polymorphic_get<const vbase>(cv).foo() == 3); + BOOST_CHECK(boost::polymorphic_get<const vbase>(v).foo() == 3); return boost::exit_success; } |