1 //-----------------------------------------------------------------------------
2 // boost variant/detail/apply_visitor_unary.hpp header file
3 // See http://www.boost.org for updates, documentation, and revision history.
4 //-----------------------------------------------------------------------------
5 //
6 // Copyright (c) 2002-2003 Eric Friedman
7 // Copyright (c) 2014 Antony Polukhin
8 //
9 // Distributed under the Boost Software License, Version 1.0. (See
10 // accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12 
13 #ifndef BOOST_VARIANT_DETAIL_APPLY_VISITOR_UNARY_HPP
14 #define BOOST_VARIANT_DETAIL_APPLY_VISITOR_UNARY_HPP
15 
16 #include <boost/config.hpp>
17 #include <boost/detail/workaround.hpp>
18 #include <boost/variant/detail/generic_result_type.hpp>
19 
20 #if BOOST_WORKAROUND(__EDG__, BOOST_TESTED_AT(302))
21 #include <boost/core/enable_if.hpp>
22 #include <boost/mpl/not.hpp>
23 #include <boost/type_traits/is_const.hpp>
24 #endif
25 
26 #if !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276)
27 #   include <boost/mpl/distance.hpp>
28 #   include <boost/mpl/advance.hpp>
29 #   include <boost/mpl/deref.hpp>
30 #   include <boost/mpl/size.hpp>
31 #   include <boost/utility/declval.hpp>
32 #   include <boost/core/enable_if.hpp>
33 #   include <boost/variant/detail/has_result_type.hpp>
34 #endif
35 
36 namespace boost {
37 
38 //////////////////////////////////////////////////////////////////////////
39 // function template apply_visitor(visitor, visitable)
40 //
41 // Visits visitable with visitor.
42 //
43 
44 //
45 // nonconst-visitor version:
46 //
47 
48 #if !BOOST_WORKAROUND(__EDG__, BOOST_TESTED_AT(302))
49 
50 #   define BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(V) \
51     BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename V::result_type) \
52     /**/
53 
54 #else // EDG-based compilers
55 
56 #   define BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(V) \
57     typename enable_if< \
58           mpl::not_< is_const< V > > \
59         , BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename V::result_type) \
60         >::type \
61     /**/
62 
63 #endif // EDG-based compilers workaround
64 
65 template <typename Visitor, typename Visitable>
66 inline
67     BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(Visitor)
apply_visitor(Visitor & visitor,Visitable & visitable)68 apply_visitor(Visitor& visitor, Visitable& visitable)
69 {
70     return visitable.apply_visitor(visitor);
71 }
72 
73 #undef BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE
74 
75 //
76 // const-visitor version:
77 //
78 
79 template <typename Visitor, typename Visitable>
80 inline
81     BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
apply_visitor(const Visitor & visitor,Visitable & visitable)82 apply_visitor(const Visitor& visitor, Visitable& visitable)
83 {
84     return visitable.apply_visitor(visitor);
85 }
86 
87 
88 #if !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276)
89 
90 // C++14
91 namespace detail { namespace variant {
92 
93 // This class serves only metaprogramming purposes. none of its methods must be called at runtime!
94 template <class Visitor, class Variant>
95 struct result_multideduce1 {
96     typedef typename Variant::types                 types;
97     typedef typename boost::mpl::begin<types>::type begin_it;
98     typedef typename boost::mpl::advance<
99         begin_it, boost::mpl::int_<boost::mpl::size<types>::type::value - 1>
100     >::type                                         last_it;
101 
102     // For metaprogramming purposes ONLY! Do not use this method (and class) at runtime!
visboost::detail::variant::result_multideduce1103     static Visitor& vis() BOOST_NOEXCEPT {
104         // Functions that work with lambdas must be defined in same translation unit.
105         // Because of that, we can not use `boost::decval<Visitor&>()` here.
106         Visitor&(*f)() = 0; // pointer to function
107         return f();
108     }
109 
deduce_implboost::detail::variant::result_multideduce1110     static decltype(auto) deduce_impl(last_it, unsigned /*helper*/) {
111         typedef typename boost::mpl::deref<last_it>::type value_t;
112         return vis()( boost::declval< value_t& >() );
113     }
114 
115     template <class It>
deduce_implboost::detail::variant::result_multideduce1116     static decltype(auto) deduce_impl(It, unsigned helper) {
117         typedef typename boost::mpl::next<It>::type next_t;
118         typedef typename boost::mpl::deref<It>::type value_t;
119         if (helper == boost::mpl::distance<begin_it, It>::type::value) {
120             return deduce_impl(next_t(), ++helper);
121         }
122 
123         return vis()( boost::declval< value_t& >() );
124     }
125 
deduceboost::detail::variant::result_multideduce1126     static decltype(auto) deduce() {
127         return deduce_impl(begin_it(), 0);
128     }
129 };
130 
131 template <class Visitor, class Variant>
132 struct result_wrapper1
133 {
134     typedef decltype(result_multideduce1<Visitor, Variant>::deduce()) result_type;
135 
136     Visitor& visitor_;
result_wrapper1boost::detail::variant::result_wrapper1137     explicit result_wrapper1(Visitor& visitor) BOOST_NOEXCEPT
138         : visitor_(visitor)
139     {}
140 
141     template <class T>
operator ()boost::detail::variant::result_wrapper1142     result_type operator()(T& val) const {
143         return visitor_(val);
144     }
145 };
146 
147 }} // namespace detail::variant
148 
149 template <typename Visitor, typename Visitable>
apply_visitor(Visitor & visitor,Visitable & visitable,typename boost::disable_if<boost::detail::variant::has_result_type<Visitor>>::type * =0)150 inline decltype(auto) apply_visitor(Visitor& visitor, Visitable& visitable,
151     typename boost::disable_if<
152         boost::detail::variant::has_result_type<Visitor>
153     >::type* = 0)
154 {
155     boost::detail::variant::result_wrapper1<Visitor, Visitable> cpp14_vis(visitor);
156     return visitable.apply_visitor(cpp14_vis);
157 }
158 
159 template <typename Visitor, typename Visitable>
apply_visitor(const Visitor & visitor,Visitable & visitable,typename boost::disable_if<boost::detail::variant::has_result_type<Visitor>>::type * =0)160 inline decltype(auto) apply_visitor(const Visitor& visitor, Visitable& visitable,
161     typename boost::disable_if<
162         boost::detail::variant::has_result_type<Visitor>
163     >::type* = 0)
164 {
165     boost::detail::variant::result_wrapper1<const Visitor, Visitable> cpp14_vis(visitor);
166     return visitable.apply_visitor(cpp14_vis);
167 }
168 
169 #endif // !defined(BOOST_NO_CXX14_DECLTYPE_AUTO) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276)
170 
171 } // namespace boost
172 
173 #endif // BOOST_VARIANT_DETAIL_APPLY_VISITOR_UNARY_HPP
174