2
0
mirror of https://github.com/boostorg/variant.git synced 2026-01-19 04:42:16 +00:00

Merge pull request #1 from diplay/universal-reverence-visitable

Universal reference visitables
This commit is contained in:
Antony Polukhin
2017-10-18 09:09:57 +03:00
committed by GitHub
7 changed files with 686 additions and 77 deletions

View File

@@ -30,6 +30,12 @@
# include <boost/variant/detail/has_result_type.hpp>
#endif
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
# include <boost/type_traits/is_same.hpp>
# include <boost/move/move.hpp>
# include <boost/move/utility.hpp>
#endif
namespace boost {
//////////////////////////////////////////////////////////////////////////
@@ -42,7 +48,7 @@ namespace boost {
namespace detail { namespace variant {
template <typename Visitor, typename Value1>
template <typename Visitor, typename Value1, bool MoveSemantics>
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 Value2>
typename enable_if_c<MoveSemantics && is_same<Value2, Value2>::value, 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_c<MoveSemantics && is_same<Value2, Value2>::value, 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)
@@ -72,11 +96,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, bool MoveSemantics>
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 Value1>
typename enable_if_c<MoveSemantics && is_same<Value1, Value1>::value, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type
operator()(Value1&& value1)
{
apply_visitor_binary_invoke<
Visitor
, Value1
, ! ::boost::is_lvalue_reference<Value1>::value
> invoker(visitor_, value1);
return boost::apply_visitor(invoker, ::boost::move(visitable2_));
}
template <typename Value1>
typename disable_if_c<MoveSemantics && is_same<Value1, Value1>::value, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type
operator()(Value1&& value1)
{
apply_visitor_binary_invoke<
Visitor
, Value1
, ! ::boost::is_lvalue_reference<Value1>::value
> invoker(visitor_, value1);
return boost::apply_visitor(invoker, visitable2_);
}
#else
template <typename Value1>
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 <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
)
apply_visitor( Visitor& visitor, Visitable1&& visitable1, Visitable2&& visitable2)
{
::boost::detail::variant::apply_visitor_binary_unwrap<
Visitor, Visitable2
Visitor, Visitable2, ! ::boost::is_lvalue_reference<Visitable2>::value
> 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, 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 <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
)
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<Visitable2>::value
> 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, 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 <typename Visitor, typename Value1>
template <typename Visitor, typename Value1, bool MoveSemantics>
class apply_visitor_binary_invoke_cpp14
{
Visitor& visitor_;
@@ -205,16 +296,22 @@ public: // structors
public: // visitor interfaces
template <typename Value2>
decltype(auto) operator()(Value2& value2)
decltype(auto) operator()(Value2&& value2, typename enable_if_c<MoveSemantics && is_same<Value2, Value2>::value>::type* = 0)
{
return visitor_(value1_, value2);
return visitor_(::boost::move(value1_), ::boost::forward<Value2>(value2));
}
template <typename Value2>
decltype(auto) operator()(Value2&& value2, typename disable_if_c<MoveSemantics && is_same<Value2, Value2>::value>::type* = 0)
{
return visitor_(value1_, ::boost::forward<Value2>(value2));
}
private:
apply_visitor_binary_invoke_cpp14& operator=(const apply_visitor_binary_invoke_cpp14&);
};
template <typename Visitor, typename Visitable2>
template <typename Visitor, typename Visitable2, bool MoveSemantics>
class apply_visitor_binary_unwrap_cpp14
{
Visitor& visitor_;
@@ -231,11 +328,24 @@ public: // structors
public: // visitor interfaces
template <typename Value1>
decltype(auto) operator()(Value1& value1)
decltype(auto) operator()(Value1&& value1, typename enable_if_c<MoveSemantics && is_same<Value1, Value1>::value>::type* = 0)
{
apply_visitor_binary_invoke_cpp14<
Visitor
, Value1
, ! ::boost::is_lvalue_reference<Value1>::value
> invoker(visitor_, value1);
return boost::apply_visitor(invoker, ::boost::move(visitable2_));
}
template <typename Value1>
decltype(auto) operator()(Value1&& value1, typename disable_if_c<MoveSemantics && is_same<Value1, Value1>::value>::type* = 0)
{
apply_visitor_binary_invoke_cpp14<
Visitor
, Value1
, ! ::boost::is_lvalue_reference<Value1>::value
> invoker(visitor_, value1);
return boost::apply_visitor(invoker, visitable2_);
@@ -248,31 +358,32 @@ private:
}} // namespace detail::variant
template <typename Visitor, typename Visitable1, typename Visitable2>
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<Visitor>
>::type* = 0)
{
::boost::detail::variant::apply_visitor_binary_unwrap_cpp14<
Visitor, Visitable2
Visitor, Visitable2, ! ::boost::is_lvalue_reference<Visitable2>::value
> unwrapper(visitor, visitable2);
return boost::apply_visitor(unwrapper, visitable1);
return boost::apply_visitor(unwrapper, ::boost::forward<Visitable1>(visitable1));
}
template <typename Visitor, typename Visitable1, typename Visitable2>
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<Visitor>
>::type* = 0)
{
::boost::detail::variant::apply_visitor_binary_unwrap_cpp14<
const Visitor, Visitable2
const Visitor, Visitable2, ! ::boost::is_lvalue_reference<Visitable2>::value
> unwrapper(visitor, visitable2);
return boost::apply_visitor(unwrapper, visitable1);
return boost::apply_visitor(unwrapper, ::boost::forward<Visitable1>(visitable1));
}
#endif // !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276)
} // namespace boost

View File

@@ -16,11 +16,13 @@
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/variant/detail/generic_result_type.hpp>
#include <boost/move/utility.hpp>
#if BOOST_WORKAROUND(__EDG__, BOOST_TESTED_AT(302))
#include <boost/core/enable_if.hpp>
#include <boost/mpl/not.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/remove_reference.hpp>
#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 <typename Visitor, typename Visitable>
inline
BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(Visitor)
apply_visitor(Visitor& visitor, Visitable&& visitable)
{
return ::boost::forward<Visitable>(visitable).apply_visitor(visitor);
}
#else
template <typename Visitor, typename Visitable>
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 <typename Visitor, typename Visitable>
inline
BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
apply_visitor(const Visitor& visitor, Visitable&& visitable)
{
return ::boost::forward<Visitable>(visitable).apply_visitor(visitor);
}
#else
template <typename Visitor, typename Visitable>
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 <class T>
result_type operator()(T& val) const {
return visitor_(val);
result_type operator()(T&& val) const {
return visitor_(::boost::forward<T>(val));
}
};
}} // namespace detail::variant
template <typename Visitor, typename Visitable>
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<Visitor>
>::type* = 0)
{
boost::detail::variant::result_wrapper1<Visitor, Visitable> cpp14_vis(visitor);
return visitable.apply_visitor(cpp14_vis);
boost::detail::variant::result_wrapper1<Visitor, typename remove_reference<Visitable>::type> cpp14_vis(visitor);
return ::boost::forward<Visitable>(visitable).apply_visitor(cpp14_vis);
}
template <typename Visitor, typename Visitable>
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<Visitor>
>::type* = 0)
{
boost::detail::variant::result_wrapper1<const Visitor, Visitable> cpp14_vis(visitor);
return visitable.apply_visitor(cpp14_vis);
boost::detail::variant::result_wrapper1<const Visitor, typename remove_reference<Visitable>::type> cpp14_vis(visitor);
return ::boost::forward<Visitable>(visitable).apply_visitor(cpp14_vis);
}
#endif // !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276)
} // namespace boost

View File

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

View File

@@ -30,7 +30,7 @@ namespace detail { namespace variant {
template <typename Visitor, typename Visitables, typename... Values>
inline one_by_one_visitor_and_value_referer_cpp14<Visitor, Visitables, Values... >
make_one_by_one_visitor_and_value_referer_cpp14(
Visitor& visitor, Visitables visitables, std::tuple<Values&...> values
Visitor& visitor, Visitables visitables, std::tuple<Values...> values
)
{
return one_by_one_visitor_and_value_referer_cpp14<Visitor, Visitables, Values... > (
@@ -42,12 +42,12 @@ namespace detail { namespace variant {
class one_by_one_visitor_and_value_referer_cpp14
{
Visitor& visitor_;
std::tuple<Values&...> values_;
std::tuple<Values...> values_;
Visitables visitables_;
public: // structors
one_by_one_visitor_and_value_referer_cpp14(
Visitor& visitor, Visitables visitables, std::tuple<Values&...> values
Visitor& visitor, Visitables visitables, std::tuple<Values...> values
) BOOST_NOEXCEPT
: visitor_(visitor)
, values_(values)
@@ -56,15 +56,15 @@ namespace detail { namespace variant {
public: // visitor interfaces
template <typename Value>
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&>(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
);
}
@@ -76,11 +76,11 @@ namespace detail { namespace variant {
class one_by_one_visitor_and_value_referer_cpp14<Visitor, std::tuple<>, Values...>
{
Visitor& visitor_;
std::tuple<Values&...> values_;
std::tuple<Values...> values_;
public:
one_by_one_visitor_and_value_referer_cpp14(
Visitor& visitor, std::tuple<> /*visitables*/, std::tuple<Values&...> values
Visitor& visitor, std::tuple<> /*visitables*/, std::tuple<Values...> values
) BOOST_NOEXCEPT
: visitor_(visitor)
, values_(values)
@@ -88,14 +88,14 @@ namespace detail { namespace variant {
template <class Tuple, std::size_t... I>
decltype(auto) do_call(Tuple t, index_sequence<I...>) const {
return visitor_(std::get<I>(t)...);
return visitor_(unwrap(std::get<I>(t))...);
}
template <typename Value>
decltype(auto) operator()(Value& value) const
decltype(auto) 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>()
);
}
@@ -104,7 +104,7 @@ namespace detail { namespace variant {
}} // namespace detail::variant
template <class Visitor, class T1, class T2, class T3, class... TN>
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<Visitor>
>::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<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 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<Visitor>
>::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<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)
);
}

View File

@@ -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 <typename Visitor>
template <typename Visitor, bool MoveSemantics>
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<T, T> to prenvent compilation error, because we need to use T in enable_if to make SFINAE work
template <typename T>
typename enable_if_c<MoveSemantics && is_same<T, T>::value, result_type>::type internal_visit(T&& operand, int)
{
return visitor_(::boost::move<T>(operand));
}
//using workaround with is_same<T, T> to prenvent compilation error, because we need to use T in enable_if to make SFINAE work
template <typename T>
typename disable_if_c<MoveSemantics && is_same<T, T>::value, result_type>::type internal_visit(T&& operand, int)
{
return visitor_(operand);
}
#else
template <typename T>
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<T, T> to prenvent compilation error, because we need to use T in enable_if to make SFINAE work
template <typename T>
typename enable_if<mpl::and_<MoveSemantics && is_same<T, T>::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<T, T> to prenvent compilation error, because we need to use T in enable_if to make SFINAE work
template <typename T>
typename enable_if_c<MoveSemantics && is_same<T, T>::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<T, T> to prenvent compilation error, because we need to use T in enable_if to make SFINAE work
template <typename T>
typename disable_if_c<MoveSemantics && is_same<T, T>::value, BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type)>::type
visit_impl(T&& operand, mpl::false_)
{
return visitor_(operand);
}
//using workaround with is_same<T, T> to prenvent compilation error, because we need to use T in enable_if to make SFINAE work
template <typename T>
typename disable_if<MoveSemantics && is_same<T, T>::value, BOOST_VARIANT_AUX_RETURN_VOID_TYPE>::type
visit_impl(T&& operand, mpl::true_)
{
visitor_(operand);
BOOST_VARIANT_AUX_RETURN_VOID;
}
#else
template <typename T>
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 <typename T>
@@ -2421,13 +2481,40 @@ public:
public: // visitation support
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template <typename Visitor>
BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(
typename Visitor::result_type
)
apply_visitor(Visitor& visitor) &&
{
detail::variant::invoke_visitor<Visitor, true> invoker(visitor);
return this->internal_apply_visitor(invoker);
}
template <typename Visitor>
BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(
typename Visitor::result_type
)
apply_visitor(Visitor& visitor) const&&
{
detail::variant::invoke_visitor<Visitor, true> invoker(visitor);
return this->internal_apply_visitor(invoker);
}
#endif
template <typename Visitor>
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<Visitor> invoker(visitor);
detail::variant::invoke_visitor<Visitor, false> 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<Visitor> invoker(visitor);
detail::variant::invoke_visitor<Visitor, false> invoker(visitor);
return this->internal_apply_visitor(invoker);
}

View File

@@ -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 ]
;

View File

@@ -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<std::string>(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<std::string>
{
template <class T>
std::string operator()(const T& val) const
{
return lcs(val);
}
template <class T, class V>
std::string operator()(const T& val, const V& val2) const
{
return lcs(val) + '+' + lcs(val2);
}
template <class T, class V, class P, class S>
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<std::string>
{
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template <class T>
std::string operator()(T&&) const
{
if (std::is_lvalue_reference<T>::value)
return "lvalue reference";
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));
}
template <class T, class V, class P>
std::string operator()(T&& t, V&& v, P&& p) const
{
return operator()(std::forward<T>(t), std::forward<V>(v)) + ", " + operator()(std::forward<P>(p));
}
template <class T, class V, class P, class S>
std::string operator()(T&& t, V&& v, P&& p, S&& s) const
{
return operator()(std::forward<T>(t), std::forward<V>(v), std::forward<P>(p)) + ", " + operator()(std::forward<S>(s));
}
#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";
}
template <class T, class V, class P>
std::string operator()(T&, V&, P&) const
{
return "lvalue reference, lvalue reference, lvalue reference";
}
template <class T, class V, class P, class S>
std::string operator()(T&, V&, P&, S&) const
{
return "lvalue reference, lvalue reference, lvalue reference, lvalue reference";
}
#endif
};
typedef boost::variant<construction_logger, std::string> 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<decltype(x)>(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<const variant_type&>(variant_type(10))) == "lvalue reference, lvalue reference");
std::cout << "Testing rvalue + lvalue visitable\n";
BOOST_CHECK(boost::apply_visitor(lvalue_rvalue_detector(), static_cast<const variant_type&>(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<const variant_type&>(variant_type(10)), v1, static_cast<const variant_type&>(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<const variant_type&>(variant_type(10)), v2, static_cast<const variant_type&>(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;
}