2
0
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:
diplay
2017-10-12 12:30:25 +03:00
parent 6d0566898e
commit 51f5b50dc9
2 changed files with 116 additions and 27 deletions

View File

@@ -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)

View File

@@ -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)