]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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) | |
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) | |
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! | |
103 | 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 | ||
110 | 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> | |
116 | 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 | ||
126 | 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_; | |
137 | explicit result_wrapper1(Visitor& visitor) BOOST_NOEXCEPT | |
138 | : visitor_(visitor) | |
139 | {} | |
140 | ||
141 | template <class T> | |
142 | result_type operator()(T& val) const { | |
143 | return visitor_(val); | |
144 | } | |
145 | }; | |
146 | ||
147 | }} // namespace detail::variant | |
148 | ||
149 | template <typename Visitor, typename Visitable> | |
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> | |
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 |