diff options
Diffstat (limited to 'boost/variant/detail/multivisitors_cpp11_based.hpp')
-rw-r--r-- | boost/variant/detail/multivisitors_cpp11_based.hpp | 84 |
1 files changed, 59 insertions, 25 deletions
diff --git a/boost/variant/detail/multivisitors_cpp11_based.hpp b/boost/variant/detail/multivisitors_cpp11_based.hpp index f9286b7dfd..56aaf125c8 100644 --- a/boost/variant/detail/multivisitors_cpp11_based.hpp +++ b/boost/variant/detail/multivisitors_cpp11_based.hpp @@ -18,6 +18,9 @@ #include <boost/variant/detail/apply_visitor_unary.hpp> #include <boost/variant/variant_fwd.hpp> // for BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES +#include <boost/move/utility.hpp> +#include <boost/type_traits/is_lvalue_reference.hpp> +#include <boost/core/enable_if.hpp> #if defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_HDR_TUPLE) # error "This file requires <tuple> and variadic templates support" @@ -41,10 +44,34 @@ namespace detail { namespace variant { : index_sequence<I...> {}; - template <class... Types> - std::tuple<Types&...> forward_as_tuple_simple(Types&... args) BOOST_NOEXCEPT + template <typename T_, bool MoveSemantics_> + struct MoveableWrapper //Just a reference with some metadata { - return std::tuple<Types&...>(args...); + typedef T_ T; + static constexpr bool MoveSemantics = MoveSemantics_; + + T& v; + }; + + template <typename Tp, bool MoveSemantics> + MoveableWrapper<Tp, MoveSemantics> + wrap(Tp& t) + { + return MoveableWrapper<Tp, MoveSemantics>{t}; + } + + template <typename Wrapper> + typename enable_if_c<Wrapper::MoveSemantics, typename Wrapper::T>::type + unwrap(Wrapper& w) + { + return ::boost::move(w.v); + } + + template <typename Wrapper> + typename disable_if_c<Wrapper::MoveSemantics, typename Wrapper::T>::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 <typename Visitor, typename Visitables, typename... Values> class one_by_one_visitor_and_value_referer; @@ -72,7 +98,7 @@ namespace detail { namespace variant { template <typename Visitor, typename Visitables, typename... Values> inline one_by_one_visitor_and_value_referer<Visitor, Visitables, Values... > make_one_by_one_visitor_and_value_referer( - Visitor& visitor, Visitables visitables, std::tuple<Values&...> values + Visitor& visitor, Visitables visitables, std::tuple<Values...> values ) { return one_by_one_visitor_and_value_referer<Visitor, Visitables, Values... > ( @@ -84,12 +110,12 @@ namespace detail { namespace variant { class one_by_one_visitor_and_value_referer { Visitor& visitor_; - std::tuple<Values&...> values_; + std::tuple<Values...> values_; Visitables visitables_; public: // structors one_by_one_visitor_and_value_referer( - Visitor& visitor, Visitables visitables, std::tuple<Values&...> values + Visitor& visitor, Visitables visitables, std::tuple<Values...> values ) BOOST_NOEXCEPT : visitor_(visitor) , values_(values) @@ -100,15 +126,15 @@ namespace detail { namespace variant { typedef typename Visitor::result_type result_type; template <typename Value> - 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&>(value)) + std::tuple_cat(values_, std::make_tuple(wrap<Value, ! ::boost::is_lvalue_reference<Value>::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<Visitor, std::tuple<>, Values...> { Visitor& visitor_; - std::tuple<Values&...> values_; + std::tuple<Values...> values_; public: one_by_one_visitor_and_value_referer( - Visitor& visitor, std::tuple<> /*visitables*/, std::tuple<Values&...> values + Visitor& visitor, std::tuple<> /*visitables*/, std::tuple<Values...> values ) BOOST_NOEXCEPT : visitor_(visitor) , values_(values) @@ -134,14 +160,14 @@ namespace detail { namespace variant { template <class Tuple, std::size_t... I> BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) do_call(Tuple t, index_sequence<I...>) const { - return visitor_(std::get<I>(t)...); + return visitor_(unwrap(std::get<I>(t))...); } template <typename Value> - 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&>(value)), + std::tuple_cat(values_, std::make_tuple(wrap<Value, ! ::boost::is_lvalue_reference<Value>::value>(value))), make_index_sequence<sizeof...(Values) + 1>() ); } @@ -151,30 +177,38 @@ namespace detail { namespace variant { template <class Visitor, class T1, class T2, class T3, class... TN> 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<T2, ! ::boost::is_lvalue_reference<T2>::value>(v2), + ::boost::detail::variant::wrap<T3, ! ::boost::is_lvalue_reference<T3>::value>(v3), + ::boost::detail::variant::wrap<TN, ! ::boost::is_lvalue_reference<TN>::value>(vn)... + ), std::tuple<>() - ), - v1 - ); + ), + ::boost::forward<T1>(v1) + ); } template <class Visitor, class T1, class T2, class T3, class... TN> 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<T2, ! ::boost::is_lvalue_reference<T2>::value>(v2), + ::boost::detail::variant::wrap<T3, ! ::boost::is_lvalue_reference<T3>::value>(v3), + ::boost::detail::variant::wrap<TN, ! ::boost::is_lvalue_reference<TN>::value>(vn)... + ), std::tuple<>() - ), - v1 - ); + ), + ::boost::forward<T1>(v1) + ); } } // namespace boost |