From cbdb354a274c8ab51a15dd43eafd02c2b6a576f0 Mon Sep 17 00:00:00 2001 From: Edward Catmur Date: Wed, 17 Apr 2019 15:05:37 +0100 Subject: [PATCH 1/2] Copy variant cvref when determining result type Ensures that we can e.g. call apply_visitor on a lvalue variant --- boost/variant/detail/apply_visitor_unary.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/boost/variant/detail/apply_visitor_unary.hpp b/boost/variant/detail/apply_visitor_unary.hpp index 71610cb6..c3a741ef 100644 --- a/boost/variant/detail/apply_visitor_unary.hpp +++ b/boost/variant/detail/apply_visitor_unary.hpp @@ -23,6 +23,7 @@ # include # include # include +# include # include # include #endif @@ -85,7 +86,7 @@ namespace detail { namespace variant { // This class serves only metaprogramming purposes. none of its methods must be called at runtime! template struct result_multideduce1 { - typedef typename Variant::types types; + typedef typename remove_reference::type::types types; typedef typename boost::mpl::begin::type begin_it; typedef typename boost::mpl::advance< begin_it, boost::mpl::int_::type::value - 1> @@ -95,14 +96,14 @@ struct result_multideduce1 { struct deduce_impl { typedef typename boost::mpl::next::type next_t; typedef typename boost::mpl::deref::type value_t; - typedef decltype(true ? boost::declval< Visitor& >()( boost::declval< value_t >() ) + typedef decltype(true ? boost::declval< Visitor& >()( boost::declval< copy_cv_ref_t< value_t, Variant > >() ) : boost::declval< typename deduce_impl::type >()) type; }; template struct deduce_impl { typedef typename boost::mpl::deref::type value_t; - typedef decltype(boost::declval< Visitor& >()( boost::declval< value_t >() )) type; + typedef decltype(boost::declval< Visitor& >()( boost::declval< copy_cv_ref_t< value_t, Variant > >() )) type; }; typedef typename deduce_impl::type type; @@ -132,7 +133,7 @@ inline decltype(auto) apply_visitor(Visitor&& visitor, Visitable&& visitable, boost::detail::variant::has_result_type >::type* = 0) { - boost::detail::variant::result_wrapper1::type> cpp14_vis(::boost::forward(visitor)); + boost::detail::variant::result_wrapper1 cpp14_vis(::boost::forward(visitor)); return ::boost::forward(visitable).apply_visitor(cpp14_vis); } From 7331d648f46b6008138cbd22087b8c5c61ff7926 Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Sun, 21 Apr 2019 00:50:00 +0100 Subject: [PATCH 2/2] Add test. --- libs/variant/test/const_ref_apply_visitor.cpp | 44 ++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/libs/variant/test/const_ref_apply_visitor.cpp b/libs/variant/test/const_ref_apply_visitor.cpp index 0ec77bd4..72afff9e 100644 --- a/libs/variant/test/const_ref_apply_visitor.cpp +++ b/libs/variant/test/const_ref_apply_visitor.cpp @@ -224,6 +224,44 @@ void test_cpp14_visitor(const variant_type& test_var, const variant_type& test_v #endif } +void test_cpp14_visitor(variant_type& test_var) +{ + std::cout << "Testing lvalue visitable for c++14\n"; + + BOOST_TEST(boost::apply_visitor([](auto& v) { return lvalue_rvalue_detector()(v); }, test_var) == "lvalue reference"); +} + +void test_cpp14_mutable_visitor(variant_type& test_var) +{ + std::cout << "Testing lvalue visitable for c++14 with inline mutable lambda\n"; + + BOOST_TEST(boost::apply_visitor([](auto& v) mutable -> auto { return lvalue_rvalue_detector()(v); }, test_var) == "lvalue reference"); +} + +void test_cpp14_visitor(variant_type& test_var, variant_type& test_var2) +{ + std::cout << "Testing lvalue visitable for c++14\n"; + + BOOST_TEST(boost::apply_visitor([](auto& v, auto& vv) { return lvalue_rvalue_detector()(v, vv); }, test_var, test_var2) + == "lvalue reference, lvalue 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 lvalue visitable for c++14\n"; + + auto result = boost::apply_visitor([](auto& v, auto& t, auto& p) { return lvalue_rvalue_detector()(v, t, p); }, + test_var, test_var2, test_var3); + std::cout << "result: " << result << std::endl; + BOOST_TEST(result == "lvalue reference, lvalue reference, lvalue reference"); +#else + (void)test_var; + (void)test_var2; + (void)test_var3; +#endif +} + void test_cpp14_visitor(variant_type&& test_var) { std::cout << "Testing rvalue visitable for c++14\n"; @@ -344,8 +382,14 @@ void run_cpp14_mixed_tests() void run_cpp14_tests() { #ifndef BOOST_NO_CXX14_DECLTYPE_AUTO + variant_type const c1(10), c2(20), c3(30); variant_type v1(10), v2(20), v3(30); + test_cpp14_visitor(c1); + test_cpp14_mutable_visitor(c1); + test_cpp14_visitor(c2, c3); + test_cpp14_visitor(c1, c2, c3); + test_cpp14_visitor(v1); test_cpp14_mutable_visitor(v1); test_cpp14_visitor(v2, v3);