diff --git a/include/boost/variant/detail/apply_visitor_binary.hpp b/include/boost/variant/detail/apply_visitor_binary.hpp index 6670cd8..bfd2844 100644 --- a/include/boost/variant/detail/apply_visitor_binary.hpp +++ b/include/boost/variant/detail/apply_visitor_binary.hpp @@ -30,6 +30,12 @@ # include #endif +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +# include +# include +# include +#endif + namespace boost { ////////////////////////////////////////////////////////////////////////// @@ -42,7 +48,7 @@ namespace boost { namespace detail { namespace variant { -template +template class apply_visitor_binary_invoke { public: // visitor typedefs @@ -65,6 +71,24 @@ public: // structors public: // visitor interfaces +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + template + typename enable_if_c::value, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type + operator()(Value2&& value2) + { + return visitor_(::boost::move(value1_), ::boost::forward(value2)); + } + + template + typename disable_if_c::value, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type + operator()(Value2&& value2) + { + return visitor_(value1_, ::boost::forward(value2)); + } + +#else + template BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) operator()(Value2& value2) @@ -72,11 +96,13 @@ public: // visitor interfaces return visitor_(value1_, value2); } +#endif + private: apply_visitor_binary_invoke& operator=(const apply_visitor_binary_invoke&); }; -template +template class apply_visitor_binary_unwrap { public: // visitor typedefs @@ -99,6 +125,36 @@ public: // structors public: // visitor interfaces +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + template + typename enable_if_c::value, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type + operator()(Value1&& value1) + { + apply_visitor_binary_invoke< + Visitor + , Value1 + , ! ::boost::is_lvalue_reference::value + > invoker(visitor_, value1); + + return boost::apply_visitor(invoker, ::boost::move(visitable2_)); + } + + template + typename disable_if_c::value, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type + operator()(Value1&& value1) + { + apply_visitor_binary_invoke< + Visitor + , Value1 + , ! ::boost::is_lvalue_reference::value + > invoker(visitor_, value1); + + return boost::apply_visitor(invoker, visitable2_); + } + +#else + template BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) operator()(Value1& value1) @@ -106,11 +162,14 @@ public: // visitor interfaces apply_visitor_binary_invoke< Visitor , Value1 + , false > invoker(visitor_, value1); return boost::apply_visitor(invoker, visitable2_); } +#endif + private: apply_visitor_binary_unwrap& operator=(const apply_visitor_binary_unwrap&); @@ -139,44 +198,76 @@ private: #endif // EDG-based compilers workaround +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template inline BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(Visitor) -apply_visitor( - Visitor& visitor - , Visitable1& visitable1, Visitable2& visitable2 - ) +apply_visitor( Visitor& visitor, Visitable1&& visitable1, Visitable2&& visitable2) { ::boost::detail::variant::apply_visitor_binary_unwrap< - Visitor, Visitable2 + Visitor, Visitable2, ! ::boost::is_lvalue_reference::value + > unwrapper(visitor, visitable2); + + return boost::apply_visitor(unwrapper, ::boost::forward(visitable1)); +} + +#else + +template +inline + BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(Visitor) +apply_visitor( Visitor& visitor, Visitable1& visitable1, Visitable2& visitable2) +{ + ::boost::detail::variant::apply_visitor_binary_unwrap< + Visitor, Visitable2, false > unwrapper(visitor, visitable2); return boost::apply_visitor(unwrapper, visitable1); } +#endif + #undef BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE // // const-visitor version: // +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template inline BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( typename Visitor::result_type ) -apply_visitor( - const Visitor& visitor - , Visitable1& visitable1, Visitable2& visitable2 - ) +apply_visitor( const Visitor& visitor , Visitable1&& visitable1 , Visitable2&& visitable2) { ::boost::detail::variant::apply_visitor_binary_unwrap< - const Visitor, Visitable2 + const Visitor, Visitable2, ! ::boost::is_lvalue_reference::value + > unwrapper(visitor, visitable2); + + return boost::apply_visitor(unwrapper, ::boost::forward(visitable1)); +} + +#else + +template +inline + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( + typename Visitor::result_type + ) +apply_visitor( const Visitor& visitor , Visitable1& visitable1 , Visitable2& visitable2) +{ + ::boost::detail::variant::apply_visitor_binary_unwrap< + const Visitor, Visitable2, false > unwrapper(visitor, visitable2); return boost::apply_visitor(unwrapper, visitable1); } +#endif + #if !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276) @@ -188,7 +279,7 @@ apply_visitor( namespace detail { namespace variant { -template +template class apply_visitor_binary_invoke_cpp14 { Visitor& visitor_; @@ -205,16 +296,22 @@ public: // structors public: // visitor interfaces template - decltype(auto) operator()(Value2& value2) + decltype(auto) operator()(Value2&& value2, typename enable_if_c::value>::type* = 0) { - return visitor_(value1_, value2); + return visitor_(::boost::move(value1_), ::boost::forward(value2)); + } + + template + decltype(auto) operator()(Value2&& value2, typename disable_if_c::value>::type* = 0) + { + return visitor_(value1_, ::boost::forward(value2)); } private: apply_visitor_binary_invoke_cpp14& operator=(const apply_visitor_binary_invoke_cpp14&); }; -template +template class apply_visitor_binary_unwrap_cpp14 { Visitor& visitor_; @@ -231,11 +328,24 @@ public: // structors public: // visitor interfaces template - decltype(auto) operator()(Value1& value1) + decltype(auto) operator()(Value1&& value1, typename enable_if_c::value>::type* = 0) { apply_visitor_binary_invoke_cpp14< Visitor , Value1 + , ! ::boost::is_lvalue_reference::value + > invoker(visitor_, value1); + + return boost::apply_visitor(invoker, ::boost::move(visitable2_)); + } + + template + decltype(auto) operator()(Value1&& value1, typename disable_if_c::value>::type* = 0) + { + apply_visitor_binary_invoke_cpp14< + Visitor + , Value1 + , ! ::boost::is_lvalue_reference::value > invoker(visitor_, value1); return boost::apply_visitor(invoker, visitable2_); @@ -248,31 +358,32 @@ private: }} // namespace detail::variant template -inline decltype(auto) apply_visitor(Visitor& visitor, Visitable1& visitable1, Visitable2& visitable2, +inline decltype(auto) apply_visitor(Visitor& visitor, Visitable1&& visitable1, Visitable2&& visitable2, typename boost::disable_if< boost::detail::variant::has_result_type >::type* = 0) { ::boost::detail::variant::apply_visitor_binary_unwrap_cpp14< - Visitor, Visitable2 + Visitor, Visitable2, ! ::boost::is_lvalue_reference::value > unwrapper(visitor, visitable2); - return boost::apply_visitor(unwrapper, visitable1); + return boost::apply_visitor(unwrapper, ::boost::forward(visitable1)); } template -inline decltype(auto) apply_visitor(const Visitor& visitor, Visitable1& visitable1, Visitable2& visitable2, +inline decltype(auto) apply_visitor(const Visitor& visitor, Visitable1&& visitable1, Visitable2&& visitable2, typename boost::disable_if< boost::detail::variant::has_result_type >::type* = 0) { ::boost::detail::variant::apply_visitor_binary_unwrap_cpp14< - const Visitor, Visitable2 + const Visitor, Visitable2, ! ::boost::is_lvalue_reference::value > unwrapper(visitor, visitable2); - return boost::apply_visitor(unwrapper, visitable1); + return boost::apply_visitor(unwrapper, ::boost::forward(visitable1)); } + #endif // !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276) } // namespace boost diff --git a/include/boost/variant/detail/apply_visitor_unary.hpp b/include/boost/variant/detail/apply_visitor_unary.hpp index d4e2c16..09f70a0 100644 --- a/include/boost/variant/detail/apply_visitor_unary.hpp +++ b/include/boost/variant/detail/apply_visitor_unary.hpp @@ -16,11 +16,13 @@ #include #include #include +#include #if BOOST_WORKAROUND(__EDG__, BOOST_TESTED_AT(302)) #include #include #include +#include #endif #if !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276) @@ -62,6 +64,15 @@ namespace boost { #endif // EDG-based compilers workaround +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +template +inline + BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(Visitor) +apply_visitor(Visitor& visitor, Visitable&& visitable) +{ + return ::boost::forward(visitable).apply_visitor(visitor); +} +#else template inline BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(Visitor) @@ -69,6 +80,7 @@ apply_visitor(Visitor& visitor, Visitable& visitable) { return visitable.apply_visitor(visitor); } +#endif #undef BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE @@ -76,6 +88,15 @@ apply_visitor(Visitor& visitor, Visitable& visitable) // const-visitor version: // +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +template +inline + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type) +apply_visitor(const Visitor& visitor, Visitable&& visitable) +{ + return ::boost::forward(visitable).apply_visitor(visitor); +} +#else template inline BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type) @@ -83,6 +104,7 @@ apply_visitor(const Visitor& visitor, Visitable& visitable) { return visitable.apply_visitor(visitor); } +#endif #if !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276) @@ -139,33 +161,34 @@ struct result_wrapper1 {} template - result_type operator()(T& val) const { - return visitor_(val); + result_type operator()(T&& val) const { + return visitor_(::boost::forward(val)); } }; }} // namespace detail::variant template -inline decltype(auto) apply_visitor(Visitor& visitor, Visitable& visitable, +inline decltype(auto) apply_visitor(Visitor& visitor, Visitable&& visitable, typename boost::disable_if< boost::detail::variant::has_result_type >::type* = 0) { - boost::detail::variant::result_wrapper1 cpp14_vis(visitor); - return visitable.apply_visitor(cpp14_vis); + boost::detail::variant::result_wrapper1::type> cpp14_vis(visitor); + return ::boost::forward(visitable).apply_visitor(cpp14_vis); } template -inline decltype(auto) apply_visitor(const Visitor& visitor, Visitable& visitable, +inline decltype(auto) apply_visitor(const Visitor& visitor, Visitable&& visitable, typename boost::disable_if< boost::detail::variant::has_result_type >::type* = 0) { - boost::detail::variant::result_wrapper1 cpp14_vis(visitor); - return visitable.apply_visitor(cpp14_vis); + boost::detail::variant::result_wrapper1::type> cpp14_vis(visitor); + return ::boost::forward(visitable).apply_visitor(cpp14_vis); } + #endif // !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276) } // namespace boost diff --git a/include/boost/variant/detail/multivisitors_cpp11_based.hpp b/include/boost/variant/detail/multivisitors_cpp11_based.hpp index f9286b7..56aaf12 100644 --- a/include/boost/variant/detail/multivisitors_cpp11_based.hpp +++ b/include/boost/variant/detail/multivisitors_cpp11_based.hpp @@ -18,6 +18,9 @@ #include #include // for BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES +#include +#include +#include #if defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_HDR_TUPLE) # error "This file requires and variadic templates support" @@ -41,10 +44,34 @@ namespace detail { namespace variant { : index_sequence {}; - template - std::tuple forward_as_tuple_simple(Types&... args) BOOST_NOEXCEPT + template + struct MoveableWrapper //Just a reference with some metadata { - return std::tuple(args...); + typedef T_ T; + static constexpr bool MoveSemantics = MoveSemantics_; + + T& v; + }; + + template + MoveableWrapper + wrap(Tp& t) + { + return MoveableWrapper{t}; + } + + template + typename enable_if_c::type + unwrap(Wrapper& w) + { + return ::boost::move(w.v); + } + + template + typename disable_if_c::type & + unwrap(Wrapper& w) + { + return w.v; } // Implementing some of the helper tuple methods @@ -64,7 +91,6 @@ namespace detail { namespace variant { } - // Forward declaration template class one_by_one_visitor_and_value_referer; @@ -72,7 +98,7 @@ namespace detail { namespace variant { template inline one_by_one_visitor_and_value_referer make_one_by_one_visitor_and_value_referer( - Visitor& visitor, Visitables visitables, std::tuple values + Visitor& visitor, Visitables visitables, std::tuple values ) { return one_by_one_visitor_and_value_referer ( @@ -84,12 +110,12 @@ namespace detail { namespace variant { class one_by_one_visitor_and_value_referer { Visitor& visitor_; - std::tuple values_; + std::tuple values_; Visitables visitables_; public: // structors one_by_one_visitor_and_value_referer( - Visitor& visitor, Visitables visitables, std::tuple values + Visitor& visitor, Visitables visitables, std::tuple values ) BOOST_NOEXCEPT : visitor_(visitor) , values_(values) @@ -100,15 +126,15 @@ namespace detail { namespace variant { typedef typename Visitor::result_type result_type; template - BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) operator()(Value& value) const + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) operator()(Value&& value) const { return ::boost::apply_visitor( make_one_by_one_visitor_and_value_referer( visitor_, tuple_tail(visitables_), - std::tuple_cat(values_, std::tuple(value)) + std::tuple_cat(values_, std::make_tuple(wrap::value>(value))) ) - , std::get<0>(visitables_) // getting Head element + , unwrap(std::get<0>(visitables_)) // getting Head element ); } @@ -120,11 +146,11 @@ namespace detail { namespace variant { class one_by_one_visitor_and_value_referer, Values...> { Visitor& visitor_; - std::tuple values_; + std::tuple values_; public: one_by_one_visitor_and_value_referer( - Visitor& visitor, std::tuple<> /*visitables*/, std::tuple values + Visitor& visitor, std::tuple<> /*visitables*/, std::tuple values ) BOOST_NOEXCEPT : visitor_(visitor) , values_(values) @@ -134,14 +160,14 @@ namespace detail { namespace variant { template BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) do_call(Tuple t, index_sequence) const { - return visitor_(std::get(t)...); + return visitor_(unwrap(std::get(t))...); } template - BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) operator()(Value& value) const + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) operator()(Value&& value) const { return do_call( - std::tuple_cat(values_, std::tuple(value)), + std::tuple_cat(values_, std::make_tuple(wrap::value>(value))), make_index_sequence() ); } @@ -151,30 +177,38 @@ namespace detail { namespace variant { template inline BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type) - apply_visitor(const Visitor& visitor, T1& v1, T2& v2, T3& v3, TN&... vn) + apply_visitor(const Visitor& visitor, T1&& v1, T2&& v2, T3&& v3, TN&&... vn) { return ::boost::apply_visitor( ::boost::detail::variant::make_one_by_one_visitor_and_value_referer( visitor, - ::boost::detail::variant::forward_as_tuple_simple(v2, v3, vn...), + std::make_tuple( + ::boost::detail::variant::wrap::value>(v2), + ::boost::detail::variant::wrap::value>(v3), + ::boost::detail::variant::wrap::value>(vn)... + ), std::tuple<>() - ), - v1 - ); + ), + ::boost::forward(v1) + ); } template inline BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type) - apply_visitor(Visitor& visitor, T1& v1, T2& v2, T3& v3, TN&... vn) + apply_visitor(Visitor& visitor, T1&& v1, T2&& v2, T3&& v3, TN&&... vn) { return ::boost::apply_visitor( ::boost::detail::variant::make_one_by_one_visitor_and_value_referer( visitor, - ::boost::detail::variant::forward_as_tuple_simple(v2, v3, vn...), + std::make_tuple( + ::boost::detail::variant::wrap::value>(v2), + ::boost::detail::variant::wrap::value>(v3), + ::boost::detail::variant::wrap::value>(vn)... + ), std::tuple<>() - ), - v1 - ); + ), + ::boost::forward(v1) + ); } } // namespace boost diff --git a/include/boost/variant/detail/multivisitors_cpp14_based.hpp b/include/boost/variant/detail/multivisitors_cpp14_based.hpp index a2af328..abf03eb 100644 --- a/include/boost/variant/detail/multivisitors_cpp14_based.hpp +++ b/include/boost/variant/detail/multivisitors_cpp14_based.hpp @@ -30,7 +30,7 @@ namespace detail { namespace variant { template inline one_by_one_visitor_and_value_referer_cpp14 make_one_by_one_visitor_and_value_referer_cpp14( - Visitor& visitor, Visitables visitables, std::tuple values + Visitor& visitor, Visitables visitables, std::tuple values ) { return one_by_one_visitor_and_value_referer_cpp14 ( @@ -42,12 +42,12 @@ namespace detail { namespace variant { class one_by_one_visitor_and_value_referer_cpp14 { Visitor& visitor_; - std::tuple values_; + std::tuple values_; Visitables visitables_; public: // structors one_by_one_visitor_and_value_referer_cpp14( - Visitor& visitor, Visitables visitables, std::tuple values + Visitor& visitor, Visitables visitables, std::tuple values ) BOOST_NOEXCEPT : visitor_(visitor) , values_(values) @@ -56,15 +56,15 @@ namespace detail { namespace variant { public: // visitor interfaces template - decltype(auto) operator()(Value& value) const + decltype(auto) operator()(Value&& value) const { return ::boost::apply_visitor( make_one_by_one_visitor_and_value_referer_cpp14( visitor_, tuple_tail(visitables_), - std::tuple_cat(values_, std::tuple(value)) + std::tuple_cat(values_, std::make_tuple(wrap::value>(value))) ) - , std::get<0>(visitables_) // getting Head element + , unwrap(std::get<0>(visitables_)) // getting Head element ); } @@ -76,11 +76,11 @@ namespace detail { namespace variant { class one_by_one_visitor_and_value_referer_cpp14, Values...> { Visitor& visitor_; - std::tuple values_; + std::tuple values_; public: one_by_one_visitor_and_value_referer_cpp14( - Visitor& visitor, std::tuple<> /*visitables*/, std::tuple values + Visitor& visitor, std::tuple<> /*visitables*/, std::tuple values ) BOOST_NOEXCEPT : visitor_(visitor) , values_(values) @@ -88,14 +88,14 @@ namespace detail { namespace variant { template decltype(auto) do_call(Tuple t, index_sequence) const { - return visitor_(std::get(t)...); + return visitor_(unwrap(std::get(t))...); } template - decltype(auto) operator()(Value& value) const + decltype(auto) operator()(Value&& value) const { return do_call( - std::tuple_cat(values_, std::tuple(value)), + std::tuple_cat(values_, std::make_tuple(wrap::value>(value))), make_index_sequence() ); } @@ -104,7 +104,7 @@ namespace detail { namespace variant { }} // namespace detail::variant template - inline decltype(auto) apply_visitor(const Visitor& visitor, T1& v1, T2& v2, T3& v3, TN&... vn, + inline decltype(auto) apply_visitor(const Visitor& visitor, T1&& v1, T2&& v2, T3&& v3, TN&&... vn, typename boost::disable_if< boost::detail::variant::has_result_type >::type* = 0) @@ -112,16 +112,20 @@ namespace detail { namespace variant { return boost::apply_visitor( ::boost::detail::variant::make_one_by_one_visitor_and_value_referer_cpp14( visitor, - ::boost::detail::variant::forward_as_tuple_simple(v2, v3, vn...), + std::make_tuple( + ::boost::detail::variant::wrap::value>(v2), + ::boost::detail::variant::wrap::value>(v3), + ::boost::detail::variant::wrap::value>(vn)... + ), std::tuple<>() ), - v1 + ::boost::forward(v1) ); } template - inline decltype(auto) apply_visitor(Visitor& visitor, T1& v1, T2& v2, T3& v3, TN&... vn, + inline decltype(auto) apply_visitor(Visitor& visitor, T1&& v1, T2&& v2, T3&& v3, TN&&... vn, typename boost::disable_if< boost::detail::variant::has_result_type >::type* = 0) @@ -129,10 +133,14 @@ namespace detail { namespace variant { return ::boost::apply_visitor( ::boost::detail::variant::make_one_by_one_visitor_and_value_referer_cpp14( visitor, - ::boost::detail::variant::forward_as_tuple_simple(v2, v3, vn...), + std::make_tuple( + ::boost::detail::variant::wrap::value>(v2), + ::boost::detail::variant::wrap::value>(v3), + ::boost::detail::variant::wrap::value>(vn)... + ), std::tuple<>() ), - v1 + ::boost::forward(v1) ); } diff --git a/include/boost/variant/variant.hpp b/include/boost/variant/variant.hpp index c3e2ccf..3e315f3 100644 --- a/include/boost/variant/variant.hpp +++ b/include/boost/variant/variant.hpp @@ -1019,7 +1019,7 @@ struct less_comp // * for wrappers (e.g., recursive_wrapper), the wrapper's held value. // * for all other values, the value itself. // -template +template class invoke_visitor { private: // representation @@ -1042,6 +1042,24 @@ public: // structors public: // internal visitor interfaces +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + //using workaround with is_same to prenvent compilation error, because we need to use T in enable_if to make SFINAE work + template + typename enable_if_c::value, result_type>::type internal_visit(T&& operand, int) + { + return visitor_(::boost::move(operand)); + } + + //using workaround with is_same to prenvent compilation error, because we need to use T in enable_if to make SFINAE work + template + typename disable_if_c::value, result_type>::type internal_visit(T&& operand, int) + { + return visitor_(operand); + } + +#else + template result_type internal_visit(T& operand, int) { @@ -1054,12 +1072,52 @@ public: // internal visitor interfaces { return visitor_(operand); } -# endif +# endif //BORLAND + +#endif //RVALUE REFERENCES #else // defined(BOOST_NO_VOID_RETURNS) private: // helpers, for internal visitor interfaces (below) +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + //using workaround with is_same to prenvent compilation error, because we need to use T in enable_if to make SFINAE work + template + typename enable_if::value>, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type + visit_impl(T&& operand, mpl::false_) + { + return visitor_(::boost::move(operand)); + } + + //using workaround with is_same to prenvent compilation error, because we need to use T in enable_if to make SFINAE work + template + typename enable_if_c::value, BOOST_VARIANT_AUX_RETURN_VOID_TYPE>::type + visit_impl(T&& operand, mpl::true_) + { + visitor_(::boost::move(operand)); + BOOST_VARIANT_AUX_RETURN_VOID; + } + + //using workaround with is_same to prenvent compilation error, because we need to use T in enable_if to make SFINAE work + template + typename disable_if_c::value, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type + visit_impl(T&& operand, mpl::false_) + { + return visitor_(operand); + } + + //using workaround with is_same to prenvent compilation error, because we need to use T in enable_if to make SFINAE work + template + typename disable_if::value, BOOST_VARIANT_AUX_RETURN_VOID_TYPE>::type + visit_impl(T&& operand, mpl::true_) + { + visitor_(operand); + BOOST_VARIANT_AUX_RETURN_VOID; + } + +#else + template BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) visit_impl(T& operand, mpl::false_) @@ -1075,6 +1133,8 @@ private: // helpers, for internal visitor interfaces (below) BOOST_VARIANT_AUX_RETURN_VOID; } +#endif //RVALUE_REFERENCES + public: // internal visitor interfaces template @@ -2421,13 +2481,40 @@ public: public: // visitation support +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + template + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( + typename Visitor::result_type + ) + apply_visitor(Visitor& visitor) && + { + detail::variant::invoke_visitor invoker(visitor); + return this->internal_apply_visitor(invoker); + } + + template + BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( + typename Visitor::result_type + ) + apply_visitor(Visitor& visitor) const&& + { + detail::variant::invoke_visitor invoker(visitor); + return this->internal_apply_visitor(invoker); + } + +#endif + template BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( typename Visitor::result_type ) apply_visitor(Visitor& visitor) +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + & +#endif { - detail::variant::invoke_visitor invoker(visitor); + detail::variant::invoke_visitor invoker(visitor); return this->internal_apply_visitor(invoker); } @@ -2436,8 +2523,11 @@ public: // visitation support typename Visitor::result_type ) apply_visitor(Visitor& visitor) const +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + & +#endif { - detail::variant::invoke_visitor invoker(visitor); + detail::variant::invoke_visitor invoker(visitor); return this->internal_apply_visitor(invoker); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c071b77..ff58aba 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -53,6 +53,7 @@ test-suite variant [ run overload_selection.cpp ] [ run recursive_wrapper_move_test.cpp ] [ run variant_over_joint_view_test.cpp ] + [ run const_ref_apply_visitor.cpp ] ; diff --git a/test/const_ref_apply_visitor.cpp b/test/const_ref_apply_visitor.cpp new file mode 100644 index 0000000..2d0639d --- /dev/null +++ b/test/const_ref_apply_visitor.cpp @@ -0,0 +1,342 @@ +#include "boost/config.hpp" + +#include "boost/test/minimal.hpp" +#include "boost/variant.hpp" +#include "boost/variant/apply_visitor.hpp" +#include "boost/variant/multivisitors.hpp" +#include "boost/lexical_cast.hpp" + +#define lcs(val) boost::lexical_cast(val) + +struct construction_logger +{ + int _val; + + construction_logger(int val) : _val(val) + { + std::cout << _val << " constructed\n"; + } + + construction_logger(const construction_logger& cl) : + _val(cl._val) + { + std::cout << _val << " copy constructed\n"; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + construction_logger(construction_logger&& cl) : + _val(cl._val) + { + std::cout << _val << " move constructed\n"; + } +#endif + + friend std::ostream& operator << (std::ostream& os, const construction_logger& cl) + { + return os << cl._val; + } + + friend std::istream& operator << (std::istream& is, construction_logger& cl) + { + return is >> cl._val; + } +}; + +struct lex_streamer_explicit : boost::static_visitor +{ + template + std::string operator()(const T& val) const + { + return lcs(val); + } + + template + std::string operator()(const T& val, const V& val2) const + { + return lcs(val) + '+' + lcs(val2); + } + + template + std::string operator()(const T& val, const V& val2, const P& val3, const S& val4) const + { + return lcs(val) + '+' + lcs(val2) + '+' + lcs(val3) + '+' + lcs(val4); + } +}; + +struct lvalue_rvalue_detector : boost::static_visitor +{ +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template + std::string operator()(T&&) const + { + if (std::is_lvalue_reference::value) + return "lvalue reference"; + else + return "rvalue reference"; + } + + template + std::string operator()(T&& t, V&& v) const + { + return operator()(std::forward(t)) + ", " + operator()(std::forward(v)); + } + + template + std::string operator()(T&& t, V&& v, P&& p) const + { + return operator()(std::forward(t), std::forward(v)) + ", " + operator()(std::forward

(p)); + } + + template + std::string operator()(T&& t, V&& v, P&& p, S&& s) const + { + return operator()(std::forward(t), std::forward(v), std::forward

(p)) + ", " + operator()(std::forward(s)); + } +#else + template + std::string operator()(T&) const + { + return "lvalue reference"; + } + + template + std::string operator()(T&, V&) const + { + return "lvalue reference, lvalue reference"; + } + + template + std::string operator()(T&, V&, P&) const + { + return "lvalue reference, lvalue reference, lvalue reference"; + } + + template + std::string operator()(T&, V&, P&, S&) const + { + return "lvalue reference, lvalue reference, lvalue reference, lvalue reference"; + } +#endif +}; + +typedef boost::variant variant_type; + +void test_const_ref_parameter(const variant_type& test_var) +{ + std::cout << "Testing const lvalue reference visitable\n"; + + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), test_var) == "lvalue reference"); +} + +void test_const_ref_parameter2(const variant_type& test_var, const variant_type& test_var2) +{ + std::cout << "Testing const lvalue reference visitable\n"; + + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), test_var, test_var2) == "lvalue reference, lvalue reference"); +} + +void test_const_ref_parameter4(const variant_type& test_var, const variant_type& test_var2, const variant_type& test_var3, const variant_type& test_var4) +{ + std::cout << "Testing const lvalue reference visitable with multivisitor\n"; + + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), test_var, test_var2, test_var3, test_var4) + == "lvalue reference, lvalue reference, lvalue reference, lvalue reference"); +} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + +void test_rvalue_parameter(variant_type&& test_var) +{ + std::cout << "Testing rvalue visitable\n"; + + const auto expected_val = lcs(test_var); + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), std::move(test_var)) == "rvalue reference"); +} + +void test_rvalue_parameter2(variant_type&& test_var, variant_type&& test_var2) +{ + std::cout << "Testing rvalue visitable\n"; + + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), std::move(test_var), std::move(test_var2)) == "rvalue reference, rvalue reference"); +} + +void test_rvalue_parameter4(variant_type&& test_var, variant_type&& test_var2, variant_type&& test_var3, variant_type&& test_var4) +{ +#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + std::cout << "Testing rvalue visitable with multivisitor\n"; + + auto result = boost::apply_visitor(lvalue_rvalue_detector(), std::move(test_var), std::move(test_var2), std::move(test_var3), std::move(test_var4)); + std::cout << "result: " << result << std::endl; + BOOST_CHECK(result == "rvalue reference, rvalue reference, rvalue reference, rvalue reference"); +#endif +} + +#endif + +#ifndef BOOST_NO_CXX14_DECLTYPE_AUTO + +#define FORWARD(x) std::forward(x) + +void test_cpp14_visitor(const variant_type& test_var) +{ + std::cout << "Testing const lvalue visitable for c++14\n"; + + BOOST_CHECK(boost::apply_visitor([](auto&& v) { return lvalue_rvalue_detector()(FORWARD(v)); }, test_var) == "lvalue reference"); +} + +void test_cpp14_visitor(const variant_type& test_var, const variant_type& test_var2) +{ + std::cout << "Testing const lvalue visitable for c++14\n"; + + BOOST_CHECK(boost::apply_visitor([](auto&& v, auto&& vv) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(vv)); }, test_var, test_var2) + == "lvalue reference, lvalue reference"); +} + +void test_cpp14_visitor(const variant_type& test_var, const variant_type& test_var2, const variant_type& test_var3) +{ +#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + std::cout << "Testing const lvalue visitable for c++14\n"; + + auto result = boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); }, + test_var, test_var2, test_var3); + std::cout << "result: " << result << std::endl; + BOOST_CHECK(result == "lvalue reference, lvalue reference, lvalue reference"); +#endif +} + +void test_cpp14_visitor(variant_type&& test_var) +{ + std::cout << "Testing rvalue visitable for c++14\n"; + + BOOST_CHECK(boost::apply_visitor([](auto&& v) { return lvalue_rvalue_detector()(FORWARD(v)); }, std::move(test_var)) == "rvalue reference"); +} + +void test_cpp14_visitor(variant_type&& test_var, variant_type&& test_var2) +{ + std::cout << "Testing rvalue visitable for c++14\n"; + + BOOST_CHECK(boost::apply_visitor([](auto&& v, auto&& vv) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(vv)); }, std::move(test_var), std::move(test_var2)) + == "rvalue reference, rvalue reference"); +} + +void test_cpp14_visitor(variant_type&& test_var, variant_type&& test_var2, variant_type&& test_var3) +{ +#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + std::cout << "Testing rvalue visitable for c++14\n"; + + auto result = boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); }, + std::move(test_var), std::move(test_var2), std::move(test_var3)); + std::cout << "result: " << result << std::endl; + BOOST_CHECK(result == "rvalue reference, rvalue reference, rvalue reference"); +#endif +} + +#endif + +void run_const_lvalue_ref_tests() +{ + const variant_type v1(1), v2(2), v3(3), v4(4); + test_const_ref_parameter(v1); + test_const_ref_parameter2(v1, v2); + test_const_ref_parameter4(v1, v2, v3, v4); +} + +void run_rvalue_ref_tests() +{ +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + variant_type v1(10), v2(20), v3(30); + test_rvalue_parameter(boost::move(v1)); + test_rvalue_parameter2(boost::move(v2), boost::move(v3)); + + variant_type vv1(100), vv2(200), vv3(300), vv4(400); + test_rvalue_parameter4(boost::move(vv1), boost::move(vv2), boost::move(vv3), boost::move(vv4)); +#endif +} + +void run_mixed_tests() +{ + variant_type v1(1), v2(2); + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + std::cout << "Testing lvalue + rvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), v1, variant_type(10)) == "lvalue reference, rvalue reference"); + + std::cout << "Testing rvalue + lvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), variant_type(10), v1) == "rvalue reference, lvalue reference"); + +#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + std::cout << "Testing rvalue + lvalue + rvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), variant_type(10), v1, variant_type(20)) == "rvalue reference, lvalue reference, rvalue reference"); + + std::cout << "Testing lvalue + rvalue + lvalue + rvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), v1, variant_type(10), v2, variant_type(20)) == "lvalue reference, rvalue reference, lvalue reference, rvalue reference"); +#endif +#else + std::cout << "Testing lvalue + rvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), v1, static_cast(variant_type(10))) == "lvalue reference, lvalue reference"); + + std::cout << "Testing rvalue + lvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), static_cast(variant_type(10)), v1) == "lvalue reference, lvalue reference"); + +#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + std::cout << "Testing rvalue + lvalue + rvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), static_cast(variant_type(10)), v1, static_cast(variant_type(20))) == "lvalue reference, lvalue reference, lvalue reference"); + + std::cout << "Testing lvalue + rvalue + lvalue + rvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), v1, static_cast(variant_type(10)), v2, static_cast(variant_type(20))) == "lvalue reference, lvalue reference, lvalue reference, lvalue reference"); +#endif +#endif +} + +void run_cpp14_mixed_tests() +{ +#ifndef BOOST_NO_CXX14_DECLTYPE_AUTO + variant_type v1(1), v2(2); + + std::cout << "Testing lvalue + rvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor([](auto&& v, auto&& t) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t)); }, + v1, variant_type(10)) == "lvalue reference, rvalue reference"); + + std::cout << "Testing rvalue + lvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor([](auto&& v, auto&& t) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t)); }, + variant_type(10), v1) == "rvalue reference, lvalue reference"); + +#if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + std::cout << "Testing rvalue + lvalue + lvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); }, + variant_type(10), v1, v2) == "rvalue reference, lvalue reference, lvalue reference"); + + std::cout << "Testing lvalue + rvalue + lvalue visitable\n"; + BOOST_CHECK(boost::apply_visitor([](auto&& v, auto&& t, auto&& p) { return lvalue_rvalue_detector()(FORWARD(v), FORWARD(t), FORWARD(p)); }, + v1, variant_type(10), v2) == "lvalue reference, rvalue reference, lvalue reference"); +#endif +#endif +} + +void run_cpp14_tests() +{ +#ifndef BOOST_NO_CXX14_DECLTYPE_AUTO + variant_type v1(10), v2(20), v3(30); + + test_cpp14_visitor(v1); + test_cpp14_visitor(v2, v3); + test_cpp14_visitor(v1, v2, v3); + + test_cpp14_visitor(boost::move(v1)); + test_cpp14_visitor(boost::move(v2), boost::move(v3)); + + variant_type vv1(100), vv2(200), vv3(300); + test_cpp14_visitor(boost::move(vv1), boost::move(vv2), boost::move(vv3)); +#endif +} + +int test_main(int , char* []) +{ + run_const_lvalue_ref_tests(); + run_rvalue_ref_tests(); + run_mixed_tests(); + run_cpp14_mixed_tests(); + run_cpp14_tests(); + + return 0; +}