mirror of
https://github.com/boostorg/variant.git
synced 2026-01-19 04:42:16 +00:00
[wip] binary apply visitor move semantics
This commit is contained in:
@@ -32,6 +32,11 @@
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
# define USE_UNIVERSAL_REF
|
||||
|
||||
# include <boost/mpl/logical.hpp>
|
||||
# include <boost/type_traits/is_same.hpp>
|
||||
# include <boost/move/move.hpp>
|
||||
# include <boost/move/utility.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
@@ -46,7 +51,7 @@ namespace boost {
|
||||
|
||||
namespace detail { namespace variant {
|
||||
|
||||
template <typename Visitor, typename Value1>
|
||||
template <typename Visitor, typename Value1, typename MoveSemantics>
|
||||
class apply_visitor_binary_invoke
|
||||
{
|
||||
public: // visitor typedefs
|
||||
@@ -69,6 +74,24 @@ public: // structors
|
||||
|
||||
public: // visitor interfaces
|
||||
|
||||
#ifdef USE_UNIVERSAL_REF
|
||||
|
||||
template <typename Value2>
|
||||
typename enable_if<mpl::and_<MoveSemantics, is_same<Value2, Value2>>, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type
|
||||
operator()(Value2&& value2)
|
||||
{
|
||||
return visitor_(::boost::move(value1_), ::boost::forward<Value2>(value2));
|
||||
}
|
||||
|
||||
template <typename Value2>
|
||||
typename disable_if<mpl::and_<MoveSemantics, is_same<Value2, Value2>>, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type
|
||||
operator()(Value2&& value2)
|
||||
{
|
||||
return visitor_(value1_, ::boost::forward<Value2>(value2));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename Value2>
|
||||
BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)
|
||||
operator()(Value2& value2)
|
||||
@@ -76,11 +99,13 @@ public: // visitor interfaces
|
||||
return visitor_(value1_, value2);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
apply_visitor_binary_invoke& operator=(const apply_visitor_binary_invoke&);
|
||||
};
|
||||
|
||||
template <typename Visitor, typename Visitable2>
|
||||
template <typename Visitor, typename Visitable2, typename MoveSemantics>
|
||||
class apply_visitor_binary_unwrap
|
||||
{
|
||||
public: // visitor typedefs
|
||||
@@ -103,6 +128,36 @@ public: // structors
|
||||
|
||||
public: // visitor interfaces
|
||||
|
||||
#ifdef USE_UNIVERSAL_REF
|
||||
|
||||
template <typename Value1>
|
||||
typename enable_if<mpl::and_<MoveSemantics, is_same<Value1, Value1>>, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type
|
||||
operator()(Value1&& value1)
|
||||
{
|
||||
apply_visitor_binary_invoke<
|
||||
Visitor
|
||||
, Value1
|
||||
, mpl::not_<::boost::is_lvalue_reference<Value1>>
|
||||
> invoker(visitor_, value1);
|
||||
|
||||
return boost::apply_visitor(invoker, ::boost::move(visitable2_));
|
||||
}
|
||||
|
||||
template <typename Value1>
|
||||
typename disable_if<mpl::and_<MoveSemantics, is_same<Value1, Value1>>, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type
|
||||
operator()(Value1&& value1)
|
||||
{
|
||||
apply_visitor_binary_invoke<
|
||||
Visitor
|
||||
, Value1
|
||||
, mpl::not_<::boost::is_lvalue_reference<Value1>>
|
||||
> invoker(visitor_, value1);
|
||||
|
||||
return boost::apply_visitor(invoker, visitable2_);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename Value1>
|
||||
BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)
|
||||
operator()(Value1& value1)
|
||||
@@ -110,11 +165,14 @@ public: // visitor interfaces
|
||||
apply_visitor_binary_invoke<
|
||||
Visitor
|
||||
, Value1
|
||||
, ::boost::false_type
|
||||
> invoker(visitor_, value1);
|
||||
|
||||
return boost::apply_visitor(invoker, visitable2_);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
apply_visitor_binary_unwrap& operator=(const apply_visitor_binary_unwrap&);
|
||||
|
||||
@@ -143,56 +201,76 @@ private:
|
||||
|
||||
#endif // EDG-based compilers workaround
|
||||
|
||||
#ifdef USE_UNIVERSAL_REF
|
||||
|
||||
template <typename Visitor, typename Visitable1, typename Visitable2>
|
||||
inline
|
||||
BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(Visitor)
|
||||
apply_visitor(
|
||||
Visitor& visitor
|
||||
#ifdef USE_UNIVERSAL_REF
|
||||
, Visitable1&& visitable1
|
||||
, Visitable2&& visitable2
|
||||
#else
|
||||
, Visitable1& visitable1
|
||||
, Visitable2& visitable2
|
||||
#endif
|
||||
)
|
||||
apply_visitor( Visitor& visitor, Visitable1&& visitable1, Visitable2&& visitable2)
|
||||
{
|
||||
::boost::detail::variant::apply_visitor_binary_unwrap<
|
||||
Visitor, Visitable2
|
||||
Visitor, Visitable2, mpl::not_<::boost::is_lvalue_reference<Visitable2>>
|
||||
> unwrapper(visitor, visitable2);
|
||||
|
||||
return boost::apply_visitor(unwrapper, ::boost::forward<Visitable1>(visitable1));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename Visitor, typename Visitable1, typename Visitable2>
|
||||
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, ::boost::false_type
|
||||
> unwrapper(visitor, visitable2);
|
||||
|
||||
return boost::apply_visitor(unwrapper, visitable1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE
|
||||
|
||||
//
|
||||
// const-visitor version:
|
||||
//
|
||||
|
||||
#ifdef USE_UNIVERSAL_REF
|
||||
|
||||
template <typename Visitor, typename Visitable1, typename Visitable2>
|
||||
inline
|
||||
BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(
|
||||
typename Visitor::result_type
|
||||
)
|
||||
apply_visitor(
|
||||
const Visitor& visitor
|
||||
#ifdef USE_UNIVERSAL_REF
|
||||
, Visitable1&& visitable1
|
||||
, Visitable2&& visitable2
|
||||
#else
|
||||
, Visitable1& visitable1
|
||||
, Visitable2& visitable2
|
||||
#endif
|
||||
)
|
||||
apply_visitor( const Visitor& visitor , Visitable1&& visitable1 , Visitable2&& visitable2)
|
||||
{
|
||||
::boost::detail::variant::apply_visitor_binary_unwrap<
|
||||
const Visitor, Visitable2
|
||||
const Visitor, Visitable2, mpl::not_<::boost::is_lvalue_reference<Visitable2>>
|
||||
> unwrapper(visitor, visitable2);
|
||||
|
||||
return boost::apply_visitor(unwrapper, ::boost::forward<Visitable1>(visitable1));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename Visitor, typename Visitable1, typename Visitable2>
|
||||
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, ::boost::false_type
|
||||
> unwrapper(visitor, visitable2);
|
||||
|
||||
return boost::apply_visitor(unwrapper, visitable1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276)
|
||||
|
||||
|
||||
@@ -79,12 +79,24 @@ struct lvalue_rvalue_detector : boost::static_visitor<std::string>
|
||||
else
|
||||
return "rvalue reference";
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
std::string operator()(T&& t, V&& v) const
|
||||
{
|
||||
return operator()(std::forward<T>(t)) + ", " + operator()(std::forward<V>(v));
|
||||
}
|
||||
#else
|
||||
template <class T>
|
||||
std::string operator()(T&) const
|
||||
{
|
||||
return "lvalue reference";
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
std::string operator()(T&, V&) const
|
||||
{
|
||||
return "lvalue reference, lvalue reference";
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -101,7 +113,7 @@ void test_const_ref_parameter2(const variant_type& test_var, const variant_type&
|
||||
{
|
||||
std::cout << "Testing const lvalue reference visitable\n";
|
||||
|
||||
BOOST_CHECK(boost::apply_visitor(lex_streamer_explicit(), test_var, test_var2) == lcs(test_var) + '+' + lcs(test_var2));
|
||||
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)
|
||||
@@ -126,8 +138,7 @@ void test_rvalue_parameter2(variant_type&& test_var, variant_type&& test_var2)
|
||||
{
|
||||
std::cout << "Testing rvalue visitable\n";
|
||||
|
||||
const auto expected_val = lcs(test_var) + '+' + lcs(test_var2);
|
||||
BOOST_CHECK(boost::apply_visitor(lex_streamer_explicit(), std::move(test_var), std::move(test_var2)) == expected_val);
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user