| Patrick Williams | ceefb31 | 2016-09-11 21:12:42 -0500 | [diff] [blame] | 1 | #ifndef MAPBOX_UTIL_VARIANT_HPP | 
|  | 2 | #define MAPBOX_UTIL_VARIANT_HPP | 
|  | 3 |  | 
|  | 4 | #include <cassert> | 
|  | 5 | #include <cstddef>   // size_t | 
|  | 6 | #include <new>       // operator new | 
|  | 7 | #include <stdexcept> // runtime_error | 
|  | 8 | #include <string> | 
|  | 9 | #include <tuple> | 
|  | 10 | #include <type_traits> | 
|  | 11 | #include <typeinfo> | 
|  | 12 | #include <utility> | 
|  | 13 |  | 
|  | 14 | #include <mapbox/recursive_wrapper.hpp> | 
|  | 15 |  | 
|  | 16 | // clang-format off | 
|  | 17 | // [[deprecated]] is only available in C++14, use this for the time being | 
|  | 18 | #if __cplusplus <= 201103L | 
|  | 19 | # ifdef __GNUC__ | 
|  | 20 | #  define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated)) | 
|  | 21 | # elif defined(_MSC_VER) | 
|  | 22 | #  define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated) | 
|  | 23 | # else | 
|  | 24 | #  define MAPBOX_VARIANT_DEPRECATED | 
|  | 25 | # endif | 
|  | 26 | #else | 
|  | 27 | #  define MAPBOX_VARIANT_DEPRECATED [[deprecated]] | 
|  | 28 | #endif | 
|  | 29 |  | 
|  | 30 |  | 
|  | 31 | #ifdef _MSC_VER | 
|  | 32 | // https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx | 
|  | 33 | # ifdef NDEBUG | 
|  | 34 | #  define VARIANT_INLINE __forceinline | 
|  | 35 | # else | 
|  | 36 | #  define VARIANT_INLINE //__declspec(noinline) | 
|  | 37 | # endif | 
|  | 38 | #else | 
|  | 39 | # ifdef NDEBUG | 
|  | 40 | #  define VARIANT_INLINE //inline __attribute__((always_inline)) | 
|  | 41 | # else | 
|  | 42 | #  define VARIANT_INLINE __attribute__((noinline)) | 
|  | 43 | # endif | 
|  | 44 | #endif | 
|  | 45 | // clang-format on | 
|  | 46 |  | 
|  | 47 | // Exceptions | 
|  | 48 | #if defined( __EXCEPTIONS) || defined( _MSC_VER) | 
|  | 49 | #define HAS_EXCEPTIONS | 
|  | 50 | #endif | 
|  | 51 |  | 
|  | 52 | #define VARIANT_MAJOR_VERSION 1 | 
|  | 53 | #define VARIANT_MINOR_VERSION 1 | 
|  | 54 | #define VARIANT_PATCH_VERSION 0 | 
|  | 55 |  | 
|  | 56 | #define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION) | 
|  | 57 |  | 
|  | 58 | namespace mapbox { | 
|  | 59 | namespace util { | 
|  | 60 |  | 
|  | 61 | // XXX This should derive from std::logic_error instead of std::runtime_error. | 
|  | 62 | //     See https://github.com/mapbox/variant/issues/48 for details. | 
|  | 63 | class bad_variant_access : public std::runtime_error | 
|  | 64 | { | 
|  | 65 |  | 
|  | 66 | public: | 
|  | 67 | explicit bad_variant_access(const std::string& what_arg) | 
|  | 68 | : runtime_error(what_arg) {} | 
|  | 69 |  | 
|  | 70 | explicit bad_variant_access(const char* what_arg) | 
|  | 71 | : runtime_error(what_arg) {} | 
|  | 72 |  | 
|  | 73 | }; // class bad_variant_access | 
|  | 74 |  | 
|  | 75 | template <typename R = void> | 
|  | 76 | struct MAPBOX_VARIANT_DEPRECATED static_visitor | 
|  | 77 | { | 
|  | 78 | using result_type = R; | 
|  | 79 |  | 
|  | 80 | protected: | 
|  | 81 | static_visitor() {} | 
|  | 82 | ~static_visitor() {} | 
|  | 83 | }; | 
|  | 84 |  | 
|  | 85 | namespace detail { | 
|  | 86 |  | 
|  | 87 | static constexpr std::size_t invalid_value = std::size_t(-1); | 
|  | 88 |  | 
|  | 89 | template <typename T, typename... Types> | 
|  | 90 | struct direct_type; | 
|  | 91 |  | 
|  | 92 | template <typename T, typename First, typename... Types> | 
|  | 93 | struct direct_type<T, First, Types...> | 
|  | 94 | { | 
|  | 95 | static constexpr std::size_t index = std::is_same<T, First>::value | 
|  | 96 | ? sizeof...(Types) | 
|  | 97 | : direct_type<T, Types...>::index; | 
|  | 98 | }; | 
|  | 99 |  | 
|  | 100 | template <typename T> | 
|  | 101 | struct direct_type<T> | 
|  | 102 | { | 
|  | 103 | static constexpr std::size_t index = invalid_value; | 
|  | 104 | }; | 
|  | 105 |  | 
|  | 106 | #if __cpp_lib_logical_traits >= 201510L | 
|  | 107 |  | 
|  | 108 | using std::disjunction; | 
|  | 109 |  | 
|  | 110 | #else | 
|  | 111 |  | 
|  | 112 | template <typename...> | 
|  | 113 | struct disjunction : std::false_type {}; | 
|  | 114 |  | 
|  | 115 | template <typename B1> | 
|  | 116 | struct disjunction<B1> : B1 {}; | 
|  | 117 |  | 
|  | 118 | template <typename B1, typename B2> | 
|  | 119 | struct disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type {}; | 
|  | 120 |  | 
|  | 121 | template <typename B1, typename... Bs> | 
|  | 122 | struct disjunction<B1, Bs...> : std::conditional<B1::value, B1, disjunction<Bs...>>::type {}; | 
|  | 123 |  | 
|  | 124 | #endif | 
|  | 125 |  | 
|  | 126 | template <typename T, typename... Types> | 
|  | 127 | struct convertible_type; | 
|  | 128 |  | 
|  | 129 | template <typename T, typename First, typename... Types> | 
|  | 130 | struct convertible_type<T, First, Types...> | 
|  | 131 | { | 
|  | 132 | static constexpr std::size_t index = std::is_convertible<T, First>::value | 
|  | 133 | ? disjunction<std::is_convertible<T, Types>...>::value ? invalid_value : sizeof...(Types) | 
|  | 134 | : convertible_type<T, Types...>::index; | 
|  | 135 | }; | 
|  | 136 |  | 
|  | 137 | template <typename T> | 
|  | 138 | struct convertible_type<T> | 
|  | 139 | { | 
|  | 140 | static constexpr std::size_t index = invalid_value; | 
|  | 141 | }; | 
|  | 142 |  | 
|  | 143 | template <typename T, typename... Types> | 
|  | 144 | struct value_traits | 
|  | 145 | { | 
|  | 146 | using value_type = typename std::remove_const<typename std::remove_reference<T>::type>::type; | 
|  | 147 | static constexpr std::size_t direct_index = direct_type<value_type, Types...>::index; | 
|  | 148 | static constexpr bool is_direct = direct_index != invalid_value; | 
|  | 149 | static constexpr std::size_t index = is_direct ? direct_index : convertible_type<value_type, Types...>::index; | 
|  | 150 | static constexpr bool is_valid = index != invalid_value; | 
|  | 151 | static constexpr std::size_t tindex = is_valid ? sizeof...(Types)-index : 0; | 
|  | 152 | using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type; | 
|  | 153 | }; | 
|  | 154 |  | 
|  | 155 | template <typename T, typename R = void> | 
|  | 156 | struct enable_if_type | 
|  | 157 | { | 
|  | 158 | using type = R; | 
|  | 159 | }; | 
|  | 160 |  | 
|  | 161 | template <typename F, typename V, typename Enable = void> | 
|  | 162 | struct result_of_unary_visit | 
|  | 163 | { | 
|  | 164 | using type = typename std::result_of<F(V&)>::type; | 
|  | 165 | }; | 
|  | 166 |  | 
|  | 167 | template <typename F, typename V> | 
|  | 168 | struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type> | 
|  | 169 | { | 
|  | 170 | using type = typename F::result_type; | 
|  | 171 | }; | 
|  | 172 |  | 
|  | 173 | template <typename F, typename V, typename Enable = void> | 
|  | 174 | struct result_of_binary_visit | 
|  | 175 | { | 
|  | 176 | using type = typename std::result_of<F(V&, V&)>::type; | 
|  | 177 | }; | 
|  | 178 |  | 
|  | 179 | template <typename F, typename V> | 
|  | 180 | struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type> | 
|  | 181 | { | 
|  | 182 | using type = typename F::result_type; | 
|  | 183 | }; | 
|  | 184 |  | 
|  | 185 | template <std::size_t arg1, std::size_t... others> | 
|  | 186 | struct static_max; | 
|  | 187 |  | 
|  | 188 | template <std::size_t arg> | 
|  | 189 | struct static_max<arg> | 
|  | 190 | { | 
|  | 191 | static const std::size_t value = arg; | 
|  | 192 | }; | 
|  | 193 |  | 
|  | 194 | template <std::size_t arg1, std::size_t arg2, std::size_t... others> | 
|  | 195 | struct static_max<arg1, arg2, others...> | 
|  | 196 | { | 
|  | 197 | static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value; | 
|  | 198 | }; | 
|  | 199 |  | 
|  | 200 | template <typename... Types> | 
|  | 201 | struct variant_helper; | 
|  | 202 |  | 
|  | 203 | template <typename T, typename... Types> | 
|  | 204 | struct variant_helper<T, Types...> | 
|  | 205 | { | 
|  | 206 | VARIANT_INLINE static void destroy(const std::size_t type_index, void* data) | 
|  | 207 | { | 
|  | 208 | if (type_index == sizeof...(Types)) | 
|  | 209 | { | 
|  | 210 | reinterpret_cast<T*>(data)->~T(); | 
|  | 211 | } | 
|  | 212 | else | 
|  | 213 | { | 
|  | 214 | variant_helper<Types...>::destroy(type_index, data); | 
|  | 215 | } | 
|  | 216 | } | 
|  | 217 |  | 
|  | 218 | VARIANT_INLINE static void move(const std::size_t old_type_index, void* old_value, void* new_value) | 
|  | 219 | { | 
|  | 220 | if (old_type_index == sizeof...(Types)) | 
|  | 221 | { | 
|  | 222 | new (new_value) T(std::move(*reinterpret_cast<T*>(old_value))); | 
|  | 223 | } | 
|  | 224 | else | 
|  | 225 | { | 
|  | 226 | variant_helper<Types...>::move(old_type_index, old_value, new_value); | 
|  | 227 | } | 
|  | 228 | } | 
|  | 229 |  | 
|  | 230 | VARIANT_INLINE static void copy(const std::size_t old_type_index, const void* old_value, void* new_value) | 
|  | 231 | { | 
|  | 232 | if (old_type_index == sizeof...(Types)) | 
|  | 233 | { | 
|  | 234 | new (new_value) T(*reinterpret_cast<const T*>(old_value)); | 
|  | 235 | } | 
|  | 236 | else | 
|  | 237 | { | 
|  | 238 | variant_helper<Types...>::copy(old_type_index, old_value, new_value); | 
|  | 239 | } | 
|  | 240 | } | 
|  | 241 | }; | 
|  | 242 |  | 
|  | 243 | template <> | 
|  | 244 | struct variant_helper<> | 
|  | 245 | { | 
|  | 246 | VARIANT_INLINE static void destroy(const std::size_t, void*) {} | 
|  | 247 | VARIANT_INLINE static void move(const std::size_t, void*, void*) {} | 
|  | 248 | VARIANT_INLINE static void copy(const std::size_t, const void*, void*) {} | 
|  | 249 | }; | 
|  | 250 |  | 
|  | 251 | template <typename T> | 
|  | 252 | struct unwrapper | 
|  | 253 | { | 
|  | 254 | static T const& apply_const(T const& obj) { return obj; } | 
|  | 255 | static T& apply(T& obj) { return obj; } | 
|  | 256 | }; | 
|  | 257 |  | 
|  | 258 | template <typename T> | 
|  | 259 | struct unwrapper<recursive_wrapper<T>> | 
|  | 260 | { | 
|  | 261 | static auto apply_const(recursive_wrapper<T> const& obj) | 
|  | 262 | -> typename recursive_wrapper<T>::type const& | 
|  | 263 | { | 
|  | 264 | return obj.get(); | 
|  | 265 | } | 
|  | 266 | static auto apply(recursive_wrapper<T>& obj) | 
|  | 267 | -> typename recursive_wrapper<T>::type& | 
|  | 268 | { | 
|  | 269 | return obj.get(); | 
|  | 270 | } | 
|  | 271 | }; | 
|  | 272 |  | 
|  | 273 | template <typename T> | 
|  | 274 | struct unwrapper<std::reference_wrapper<T>> | 
|  | 275 | { | 
|  | 276 | static auto apply_const(std::reference_wrapper<T> const& obj) | 
|  | 277 | -> typename std::reference_wrapper<T>::type const& | 
|  | 278 | { | 
|  | 279 | return obj.get(); | 
|  | 280 | } | 
|  | 281 | static auto apply(std::reference_wrapper<T>& obj) | 
|  | 282 | -> typename std::reference_wrapper<T>::type& | 
|  | 283 | { | 
|  | 284 | return obj.get(); | 
|  | 285 | } | 
|  | 286 | }; | 
|  | 287 |  | 
|  | 288 | template <typename F, typename V, typename R, typename... Types> | 
|  | 289 | struct dispatcher; | 
|  | 290 |  | 
|  | 291 | template <typename F, typename V, typename R, typename T, typename... Types> | 
|  | 292 | struct dispatcher<F, V, R, T, Types...> | 
|  | 293 | { | 
|  | 294 | VARIANT_INLINE static R apply_const(V const& v, F&& f) | 
|  | 295 | { | 
|  | 296 | if (v.template is<T>()) | 
|  | 297 | { | 
|  | 298 | return f(unwrapper<T>::apply_const(v.template get_unchecked<T>())); | 
|  | 299 | } | 
|  | 300 | else | 
|  | 301 | { | 
|  | 302 | return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)); | 
|  | 303 | } | 
|  | 304 | } | 
|  | 305 |  | 
|  | 306 | VARIANT_INLINE static R apply(V& v, F&& f) | 
|  | 307 | { | 
|  | 308 | if (v.template is<T>()) | 
|  | 309 | { | 
|  | 310 | return f(unwrapper<T>::apply(v.template get_unchecked<T>())); | 
|  | 311 | } | 
|  | 312 | else | 
|  | 313 | { | 
|  | 314 | return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)); | 
|  | 315 | } | 
|  | 316 | } | 
|  | 317 | }; | 
|  | 318 |  | 
|  | 319 | template <typename F, typename V, typename R, typename T> | 
|  | 320 | struct dispatcher<F, V, R, T> | 
|  | 321 | { | 
|  | 322 | VARIANT_INLINE static R apply_const(V const& v, F&& f) | 
|  | 323 | { | 
|  | 324 | return f(unwrapper<T>::apply_const(v.template get_unchecked<T>())); | 
|  | 325 | } | 
|  | 326 |  | 
|  | 327 | VARIANT_INLINE static R apply(V& v, F&& f) | 
|  | 328 | { | 
|  | 329 | return f(unwrapper<T>::apply(v.template get_unchecked<T>())); | 
|  | 330 | } | 
|  | 331 | }; | 
|  | 332 |  | 
|  | 333 | template <typename F, typename V, typename R, typename T, typename... Types> | 
|  | 334 | struct binary_dispatcher_rhs; | 
|  | 335 |  | 
|  | 336 | template <typename F, typename V, typename R, typename T0, typename T1, typename... Types> | 
|  | 337 | struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...> | 
|  | 338 | { | 
|  | 339 | VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) | 
|  | 340 | { | 
|  | 341 | if (rhs.template is<T1>()) // call binary functor | 
|  | 342 | { | 
|  | 343 | return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()), | 
|  | 344 | unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>())); | 
|  | 345 | } | 
|  | 346 | else | 
|  | 347 | { | 
|  | 348 | return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f)); | 
|  | 349 | } | 
|  | 350 | } | 
|  | 351 |  | 
|  | 352 | VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) | 
|  | 353 | { | 
|  | 354 | if (rhs.template is<T1>()) // call binary functor | 
|  | 355 | { | 
|  | 356 | return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()), | 
|  | 357 | unwrapper<T1>::apply(rhs.template get_unchecked<T1>())); | 
|  | 358 | } | 
|  | 359 | else | 
|  | 360 | { | 
|  | 361 | return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f)); | 
|  | 362 | } | 
|  | 363 | } | 
|  | 364 | }; | 
|  | 365 |  | 
|  | 366 | template <typename F, typename V, typename R, typename T0, typename T1> | 
|  | 367 | struct binary_dispatcher_rhs<F, V, R, T0, T1> | 
|  | 368 | { | 
|  | 369 | VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) | 
|  | 370 | { | 
|  | 371 | return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()), | 
|  | 372 | unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>())); | 
|  | 373 | } | 
|  | 374 |  | 
|  | 375 | VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) | 
|  | 376 | { | 
|  | 377 | return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()), | 
|  | 378 | unwrapper<T1>::apply(rhs.template get_unchecked<T1>())); | 
|  | 379 | } | 
|  | 380 | }; | 
|  | 381 |  | 
|  | 382 | template <typename F, typename V, typename R, typename T, typename... Types> | 
|  | 383 | struct binary_dispatcher_lhs; | 
|  | 384 |  | 
|  | 385 | template <typename F, typename V, typename R, typename T0, typename T1, typename... Types> | 
|  | 386 | struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...> | 
|  | 387 | { | 
|  | 388 | VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) | 
|  | 389 | { | 
|  | 390 | if (lhs.template is<T1>()) // call binary functor | 
|  | 391 | { | 
|  | 392 | return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()), | 
|  | 393 | unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>())); | 
|  | 394 | } | 
|  | 395 | else | 
|  | 396 | { | 
|  | 397 | return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f)); | 
|  | 398 | } | 
|  | 399 | } | 
|  | 400 |  | 
|  | 401 | VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) | 
|  | 402 | { | 
|  | 403 | if (lhs.template is<T1>()) // call binary functor | 
|  | 404 | { | 
|  | 405 | return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()), | 
|  | 406 | unwrapper<T0>::apply(rhs.template get_unchecked<T0>())); | 
|  | 407 | } | 
|  | 408 | else | 
|  | 409 | { | 
|  | 410 | return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f)); | 
|  | 411 | } | 
|  | 412 | } | 
|  | 413 | }; | 
|  | 414 |  | 
|  | 415 | template <typename F, typename V, typename R, typename T0, typename T1> | 
|  | 416 | struct binary_dispatcher_lhs<F, V, R, T0, T1> | 
|  | 417 | { | 
|  | 418 | VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) | 
|  | 419 | { | 
|  | 420 | return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()), | 
|  | 421 | unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>())); | 
|  | 422 | } | 
|  | 423 |  | 
|  | 424 | VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) | 
|  | 425 | { | 
|  | 426 | return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()), | 
|  | 427 | unwrapper<T0>::apply(rhs.template get_unchecked<T0>())); | 
|  | 428 | } | 
|  | 429 | }; | 
|  | 430 |  | 
|  | 431 | template <typename F, typename V, typename R, typename... Types> | 
|  | 432 | struct binary_dispatcher; | 
|  | 433 |  | 
|  | 434 | template <typename F, typename V, typename R, typename T, typename... Types> | 
|  | 435 | struct binary_dispatcher<F, V, R, T, Types...> | 
|  | 436 | { | 
|  | 437 | VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f) | 
|  | 438 | { | 
|  | 439 | if (v0.template is<T>()) | 
|  | 440 | { | 
|  | 441 | if (v1.template is<T>()) | 
|  | 442 | { | 
|  | 443 | return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()), | 
|  | 444 | unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor | 
|  | 445 | } | 
|  | 446 | else | 
|  | 447 | { | 
|  | 448 | return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f)); | 
|  | 449 | } | 
|  | 450 | } | 
|  | 451 | else if (v1.template is<T>()) | 
|  | 452 | { | 
|  | 453 | return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f)); | 
|  | 454 | } | 
|  | 455 | return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)); | 
|  | 456 | } | 
|  | 457 |  | 
|  | 458 | VARIANT_INLINE static R apply(V& v0, V& v1, F&& f) | 
|  | 459 | { | 
|  | 460 | if (v0.template is<T>()) | 
|  | 461 | { | 
|  | 462 | if (v1.template is<T>()) | 
|  | 463 | { | 
|  | 464 | return f(unwrapper<T>::apply(v0.template get_unchecked<T>()), | 
|  | 465 | unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor | 
|  | 466 | } | 
|  | 467 | else | 
|  | 468 | { | 
|  | 469 | return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f)); | 
|  | 470 | } | 
|  | 471 | } | 
|  | 472 | else if (v1.template is<T>()) | 
|  | 473 | { | 
|  | 474 | return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f)); | 
|  | 475 | } | 
|  | 476 | return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)); | 
|  | 477 | } | 
|  | 478 | }; | 
|  | 479 |  | 
|  | 480 | template <typename F, typename V, typename R, typename T> | 
|  | 481 | struct binary_dispatcher<F, V, R, T> | 
|  | 482 | { | 
|  | 483 | VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f) | 
|  | 484 | { | 
|  | 485 | return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()), | 
|  | 486 | unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor | 
|  | 487 | } | 
|  | 488 |  | 
|  | 489 | VARIANT_INLINE static R apply(V& v0, V& v1, F&& f) | 
|  | 490 | { | 
|  | 491 | return f(unwrapper<T>::apply(v0.template get_unchecked<T>()), | 
|  | 492 | unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor | 
|  | 493 | } | 
|  | 494 | }; | 
|  | 495 |  | 
|  | 496 | // comparator functors | 
|  | 497 | struct equal_comp | 
|  | 498 | { | 
|  | 499 | template <typename T> | 
|  | 500 | bool operator()(T const& lhs, T const& rhs) const | 
|  | 501 | { | 
|  | 502 | return lhs == rhs; | 
|  | 503 | } | 
|  | 504 | }; | 
|  | 505 |  | 
|  | 506 | struct less_comp | 
|  | 507 | { | 
|  | 508 | template <typename T> | 
|  | 509 | bool operator()(T const& lhs, T const& rhs) const | 
|  | 510 | { | 
|  | 511 | return lhs < rhs; | 
|  | 512 | } | 
|  | 513 | }; | 
|  | 514 |  | 
|  | 515 | template <typename Variant, typename Comp> | 
|  | 516 | class comparer | 
|  | 517 | { | 
|  | 518 | public: | 
|  | 519 | explicit comparer(Variant const& lhs) noexcept | 
|  | 520 | : lhs_(lhs) {} | 
|  | 521 | comparer& operator=(comparer const&) = delete; | 
|  | 522 | // visitor | 
|  | 523 | template <typename T> | 
|  | 524 | bool operator()(T const& rhs_content) const | 
|  | 525 | { | 
|  | 526 | T const& lhs_content = lhs_.template get_unchecked<T>(); | 
|  | 527 | return Comp()(lhs_content, rhs_content); | 
|  | 528 | } | 
|  | 529 |  | 
|  | 530 | private: | 
|  | 531 | Variant const& lhs_; | 
|  | 532 | }; | 
|  | 533 |  | 
|  | 534 | } // namespace detail | 
|  | 535 |  | 
|  | 536 | struct no_init | 
|  | 537 | { | 
|  | 538 | }; | 
|  | 539 |  | 
|  | 540 | template <typename... Types> | 
|  | 541 | class variant | 
|  | 542 | { | 
|  | 543 | static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty"); | 
|  | 544 | static_assert(!detail::disjunction<std::is_reference<Types>...>::value, "Variant can not hold reference types. Maybe use std::reference_wrapper?"); | 
|  | 545 |  | 
|  | 546 | private: | 
|  | 547 | static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value; | 
|  | 548 | static const std::size_t data_align = detail::static_max<alignof(Types)...>::value; | 
|  | 549 |  | 
|  | 550 | using first_type = typename std::tuple_element<0, std::tuple<Types...>>::type; | 
|  | 551 | using data_type = typename std::aligned_storage<data_size, data_align>::type; | 
|  | 552 | using helper_type = detail::variant_helper<Types...>; | 
|  | 553 |  | 
|  | 554 | std::size_t type_index; | 
|  | 555 | data_type data; | 
|  | 556 |  | 
|  | 557 | public: | 
|  | 558 | VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value) | 
|  | 559 | : type_index(sizeof...(Types)-1) | 
|  | 560 | { | 
|  | 561 | static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant"); | 
|  | 562 | new (&data) first_type(); | 
|  | 563 | } | 
|  | 564 |  | 
|  | 565 | VARIANT_INLINE variant(no_init) noexcept | 
|  | 566 | : type_index(detail::invalid_value) {} | 
|  | 567 |  | 
|  | 568 | // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers | 
|  | 569 | template <typename T, typename Traits = detail::value_traits<T, Types...>, | 
|  | 570 | typename Enable = typename std::enable_if<Traits::is_valid>::type> | 
|  | 571 | VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value) | 
|  | 572 | : type_index(Traits::index) | 
|  | 573 | { | 
|  | 574 | new (&data) typename Traits::target_type(std::forward<T>(val)); | 
|  | 575 | } | 
|  | 576 |  | 
|  | 577 | VARIANT_INLINE variant(variant<Types...> const& old) | 
|  | 578 | : type_index(old.type_index) | 
|  | 579 | { | 
|  | 580 | helper_type::copy(old.type_index, &old.data, &data); | 
|  | 581 | } | 
|  | 582 |  | 
|  | 583 | VARIANT_INLINE variant(variant<Types...>&& old) noexcept(std::is_nothrow_move_constructible<std::tuple<Types...>>::value) | 
|  | 584 | : type_index(old.type_index) | 
|  | 585 | { | 
|  | 586 | helper_type::move(old.type_index, &old.data, &data); | 
|  | 587 | } | 
|  | 588 |  | 
|  | 589 | private: | 
|  | 590 | VARIANT_INLINE void copy_assign(variant<Types...> const& rhs) | 
|  | 591 | { | 
|  | 592 | helper_type::destroy(type_index, &data); | 
|  | 593 | type_index = detail::invalid_value; | 
|  | 594 | helper_type::copy(rhs.type_index, &rhs.data, &data); | 
|  | 595 | type_index = rhs.type_index; | 
|  | 596 | } | 
|  | 597 |  | 
|  | 598 | VARIANT_INLINE void move_assign(variant<Types...>&& rhs) | 
|  | 599 | { | 
|  | 600 | helper_type::destroy(type_index, &data); | 
|  | 601 | type_index = detail::invalid_value; | 
|  | 602 | helper_type::move(rhs.type_index, &rhs.data, &data); | 
|  | 603 | type_index = rhs.type_index; | 
|  | 604 | } | 
|  | 605 |  | 
|  | 606 | public: | 
|  | 607 | VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other) | 
|  | 608 | { | 
|  | 609 | move_assign(std::move(other)); | 
|  | 610 | return *this; | 
|  | 611 | } | 
|  | 612 |  | 
|  | 613 | VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other) | 
|  | 614 | { | 
|  | 615 | copy_assign(other); | 
|  | 616 | return *this; | 
|  | 617 | } | 
|  | 618 |  | 
|  | 619 | // conversions | 
|  | 620 | // move-assign | 
|  | 621 | template <typename T> | 
|  | 622 | VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept | 
|  | 623 | { | 
|  | 624 | variant<Types...> temp(std::forward<T>(rhs)); | 
|  | 625 | move_assign(std::move(temp)); | 
|  | 626 | return *this; | 
|  | 627 | } | 
|  | 628 |  | 
|  | 629 | // copy-assign | 
|  | 630 | template <typename T> | 
|  | 631 | VARIANT_INLINE variant<Types...>& operator=(T const& rhs) | 
|  | 632 | { | 
|  | 633 | variant<Types...> temp(rhs); | 
|  | 634 | copy_assign(temp); | 
|  | 635 | return *this; | 
|  | 636 | } | 
|  | 637 |  | 
|  | 638 | template <typename T, typename std::enable_if< | 
|  | 639 | (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 640 | VARIANT_INLINE bool is() const | 
|  | 641 | { | 
|  | 642 | return type_index == detail::direct_type<T, Types...>::index; | 
|  | 643 | } | 
|  | 644 |  | 
|  | 645 | template <typename T,typename std::enable_if< | 
|  | 646 | (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 647 | VARIANT_INLINE bool is() const | 
|  | 648 | { | 
|  | 649 | return type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index; | 
|  | 650 | } | 
|  | 651 |  | 
|  | 652 | VARIANT_INLINE bool valid() const | 
|  | 653 | { | 
|  | 654 | return type_index != detail::invalid_value; | 
|  | 655 | } | 
|  | 656 |  | 
|  | 657 | template <typename T, typename... Args> | 
|  | 658 | VARIANT_INLINE void set(Args&&... args) | 
|  | 659 | { | 
|  | 660 | helper_type::destroy(type_index, &data); | 
|  | 661 | type_index = detail::invalid_value; | 
|  | 662 | new (&data) T(std::forward<Args>(args)...); | 
|  | 663 | type_index = detail::direct_type<T, Types...>::index; | 
|  | 664 | } | 
|  | 665 |  | 
|  | 666 | // get_unchecked<T>() | 
|  | 667 | template <typename T, typename std::enable_if< | 
|  | 668 | (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 669 | VARIANT_INLINE T& get_unchecked() | 
|  | 670 | { | 
|  | 671 | return *reinterpret_cast<T*>(&data); | 
|  | 672 | } | 
|  | 673 |  | 
|  | 674 | #ifdef HAS_EXCEPTIONS | 
|  | 675 | // get<T>() | 
|  | 676 | template <typename T, typename std::enable_if< | 
|  | 677 | (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 678 | VARIANT_INLINE T& get() | 
|  | 679 | { | 
|  | 680 | if (type_index == detail::direct_type<T, Types...>::index) | 
|  | 681 | { | 
|  | 682 | return *reinterpret_cast<T*>(&data); | 
|  | 683 | } | 
|  | 684 | else | 
|  | 685 | { | 
|  | 686 | throw bad_variant_access("in get<T>()"); | 
|  | 687 | } | 
|  | 688 | } | 
|  | 689 | #endif | 
|  | 690 |  | 
|  | 691 | template <typename T, typename std::enable_if< | 
|  | 692 | (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 693 | VARIANT_INLINE T const& get_unchecked() const | 
|  | 694 | { | 
|  | 695 | return *reinterpret_cast<T const*>(&data); | 
|  | 696 | } | 
|  | 697 |  | 
|  | 698 | #ifdef HAS_EXCEPTIONS | 
|  | 699 | template <typename T, typename std::enable_if< | 
|  | 700 | (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 701 | VARIANT_INLINE T const& get() const | 
|  | 702 | { | 
|  | 703 | if (type_index == detail::direct_type<T, Types...>::index) | 
|  | 704 | { | 
|  | 705 | return *reinterpret_cast<T const*>(&data); | 
|  | 706 | } | 
|  | 707 | else | 
|  | 708 | { | 
|  | 709 | throw bad_variant_access("in get<T>()"); | 
|  | 710 | } | 
|  | 711 | } | 
|  | 712 | #endif | 
|  | 713 |  | 
|  | 714 | // get_unchecked<T>() - T stored as recursive_wrapper<T> | 
|  | 715 | template <typename T, typename std::enable_if< | 
|  | 716 | (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 717 | VARIANT_INLINE T& get_unchecked() | 
|  | 718 | { | 
|  | 719 | return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get(); | 
|  | 720 | } | 
|  | 721 |  | 
|  | 722 | #ifdef HAS_EXCEPTIONS | 
|  | 723 | // get<T>() - T stored as recursive_wrapper<T> | 
|  | 724 | template <typename T, typename std::enable_if< | 
|  | 725 | (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 726 | VARIANT_INLINE T& get() | 
|  | 727 | { | 
|  | 728 | if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index) | 
|  | 729 | { | 
|  | 730 | return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get(); | 
|  | 731 | } | 
|  | 732 | else | 
|  | 733 | { | 
|  | 734 | throw bad_variant_access("in get<T>()"); | 
|  | 735 | } | 
|  | 736 | } | 
|  | 737 | #endif | 
|  | 738 |  | 
|  | 739 | template <typename T, typename std::enable_if< | 
|  | 740 | (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 741 | VARIANT_INLINE T const& get_unchecked() const | 
|  | 742 | { | 
|  | 743 | return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get(); | 
|  | 744 | } | 
|  | 745 |  | 
|  | 746 | #ifdef HAS_EXCEPTIONS | 
|  | 747 | template <typename T, typename std::enable_if< | 
|  | 748 | (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 749 | VARIANT_INLINE T const& get() const | 
|  | 750 | { | 
|  | 751 | if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index) | 
|  | 752 | { | 
|  | 753 | return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get(); | 
|  | 754 | } | 
|  | 755 | else | 
|  | 756 | { | 
|  | 757 | throw bad_variant_access("in get<T>()"); | 
|  | 758 | } | 
|  | 759 | } | 
|  | 760 | #endif | 
|  | 761 |  | 
|  | 762 | // get_unchecked<T>() - T stored as std::reference_wrapper<T> | 
|  | 763 | template <typename T, typename std::enable_if< | 
|  | 764 | (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 765 | VARIANT_INLINE T& get_unchecked() | 
|  | 766 | { | 
|  | 767 | return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get(); | 
|  | 768 | } | 
|  | 769 |  | 
|  | 770 | #ifdef HAS_EXCEPTIONS | 
|  | 771 | // get<T>() - T stored as std::reference_wrapper<T> | 
|  | 772 | template <typename T, typename std::enable_if< | 
|  | 773 | (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 774 | VARIANT_INLINE T& get() | 
|  | 775 | { | 
|  | 776 | if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index) | 
|  | 777 | { | 
|  | 778 | return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get(); | 
|  | 779 | } | 
|  | 780 | else | 
|  | 781 | { | 
|  | 782 | throw bad_variant_access("in get<T>()"); | 
|  | 783 | } | 
|  | 784 | } | 
|  | 785 | #endif | 
|  | 786 |  | 
|  | 787 | template <typename T, typename std::enable_if< | 
|  | 788 | (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 789 | VARIANT_INLINE T const& get_unchecked() const | 
|  | 790 | { | 
|  | 791 | return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get(); | 
|  | 792 | } | 
|  | 793 |  | 
|  | 794 | #ifdef HAS_EXCEPTIONS | 
|  | 795 | template <typename T, typename std::enable_if< | 
|  | 796 | (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 797 | VARIANT_INLINE T const& get() const | 
|  | 798 | { | 
|  | 799 | if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index) | 
|  | 800 | { | 
|  | 801 | return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get(); | 
|  | 802 | } | 
|  | 803 | else | 
|  | 804 | { | 
|  | 805 | throw bad_variant_access("in get<T>()"); | 
|  | 806 | } | 
|  | 807 | } | 
|  | 808 | #endif | 
|  | 809 |  | 
|  | 810 | // This function is deprecated because it returns an internal index field. | 
|  | 811 | // Use which() instead. | 
|  | 812 | MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const | 
|  | 813 | { | 
|  | 814 | return type_index; | 
|  | 815 | } | 
|  | 816 |  | 
|  | 817 | VARIANT_INLINE int which() const noexcept | 
|  | 818 | { | 
|  | 819 | return static_cast<int>(sizeof...(Types)-type_index - 1); | 
|  | 820 | } | 
|  | 821 |  | 
|  | 822 | template <typename T, typename std::enable_if< | 
|  | 823 | (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr> | 
|  | 824 | VARIANT_INLINE static constexpr int which() noexcept | 
|  | 825 | { | 
|  | 826 | return static_cast<int>(sizeof...(Types)-detail::direct_type<T, Types...>::index - 1); | 
|  | 827 | } | 
|  | 828 |  | 
|  | 829 | // visitor | 
|  | 830 | // unary | 
|  | 831 | template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type> | 
|  | 832 | auto VARIANT_INLINE static visit(V const& v, F&& f) | 
|  | 833 | -> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f))) | 
|  | 834 | { | 
|  | 835 | return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)); | 
|  | 836 | } | 
|  | 837 | // non-const | 
|  | 838 | template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type> | 
|  | 839 | auto VARIANT_INLINE static visit(V& v, F&& f) | 
|  | 840 | -> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f))) | 
|  | 841 | { | 
|  | 842 | return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)); | 
|  | 843 | } | 
|  | 844 |  | 
|  | 845 | // binary | 
|  | 846 | // const | 
|  | 847 | template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type> | 
|  | 848 | auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f) | 
|  | 849 | -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f))) | 
|  | 850 | { | 
|  | 851 | return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)); | 
|  | 852 | } | 
|  | 853 | // non-const | 
|  | 854 | template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type> | 
|  | 855 | auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f) | 
|  | 856 | -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f))) | 
|  | 857 | { | 
|  | 858 | return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)); | 
|  | 859 | } | 
|  | 860 |  | 
|  | 861 | ~variant() noexcept // no-throw destructor | 
|  | 862 | { | 
|  | 863 | helper_type::destroy(type_index, &data); | 
|  | 864 | } | 
|  | 865 |  | 
|  | 866 | // comparison operators | 
|  | 867 | // equality | 
|  | 868 | VARIANT_INLINE bool operator==(variant const& rhs) const | 
|  | 869 | { | 
|  | 870 | assert(valid() && rhs.valid()); | 
|  | 871 | if (this->which() != rhs.which()) | 
|  | 872 | { | 
|  | 873 | return false; | 
|  | 874 | } | 
|  | 875 | detail::comparer<variant, detail::equal_comp> visitor(*this); | 
|  | 876 | return visit(rhs, visitor); | 
|  | 877 | } | 
|  | 878 |  | 
|  | 879 | VARIANT_INLINE bool operator!=(variant const& rhs) const | 
|  | 880 | { | 
|  | 881 | return !(*this == rhs); | 
|  | 882 | } | 
|  | 883 |  | 
|  | 884 | // less than | 
|  | 885 | VARIANT_INLINE bool operator<(variant const& rhs) const | 
|  | 886 | { | 
|  | 887 | assert(valid() && rhs.valid()); | 
|  | 888 | if (this->which() != rhs.which()) | 
|  | 889 | { | 
|  | 890 | return this->which() < rhs.which(); | 
|  | 891 | } | 
|  | 892 | detail::comparer<variant, detail::less_comp> visitor(*this); | 
|  | 893 | return visit(rhs, visitor); | 
|  | 894 | } | 
|  | 895 | VARIANT_INLINE bool operator>(variant const& rhs) const | 
|  | 896 | { | 
|  | 897 | return rhs < *this; | 
|  | 898 | } | 
|  | 899 | VARIANT_INLINE bool operator<=(variant const& rhs) const | 
|  | 900 | { | 
|  | 901 | return !(*this > rhs); | 
|  | 902 | } | 
|  | 903 | VARIANT_INLINE bool operator>=(variant const& rhs) const | 
|  | 904 | { | 
|  | 905 | return !(*this < rhs); | 
|  | 906 | } | 
|  | 907 | }; | 
|  | 908 |  | 
|  | 909 | // unary visitor interface | 
|  | 910 | // const | 
|  | 911 | template <typename F, typename V> | 
|  | 912 | auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f))) | 
|  | 913 | { | 
|  | 914 | return V::visit(v, std::forward<F>(f)); | 
|  | 915 | } | 
|  | 916 |  | 
|  | 917 | // non-const | 
|  | 918 | template <typename F, typename V> | 
|  | 919 | auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f))) | 
|  | 920 | { | 
|  | 921 | return V::visit(v, std::forward<F>(f)); | 
|  | 922 | } | 
|  | 923 |  | 
|  | 924 | // binary visitor interface | 
|  | 925 | // const | 
|  | 926 | template <typename F, typename V> | 
|  | 927 | auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f))) | 
|  | 928 | { | 
|  | 929 | return V::binary_visit(v0, v1, std::forward<F>(f)); | 
|  | 930 | } | 
|  | 931 |  | 
|  | 932 | // non-const | 
|  | 933 | template <typename F, typename V> | 
|  | 934 | auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f))) | 
|  | 935 | { | 
|  | 936 | return V::binary_visit(v0, v1, std::forward<F>(f)); | 
|  | 937 | } | 
|  | 938 |  | 
|  | 939 | // getter interface | 
|  | 940 |  | 
|  | 941 | #ifdef HAS_EXCEPTIONS | 
|  | 942 | template <typename ResultType, typename T> | 
|  | 943 | auto get(T& var)->decltype(var.template get<ResultType>()) | 
|  | 944 | { | 
|  | 945 | return var.template get<ResultType>(); | 
|  | 946 | } | 
|  | 947 | #endif | 
|  | 948 |  | 
|  | 949 | template <typename ResultType, typename T> | 
|  | 950 | ResultType& get_unchecked(T& var) | 
|  | 951 | { | 
|  | 952 | return var.template get_unchecked<ResultType>(); | 
|  | 953 | } | 
|  | 954 |  | 
|  | 955 | #ifdef HAS_EXCEPTIONS | 
|  | 956 | template <typename ResultType, typename T> | 
|  | 957 | auto get(T const& var)->decltype(var.template get<ResultType>()) | 
|  | 958 | { | 
|  | 959 | return var.template get<ResultType>(); | 
|  | 960 | } | 
|  | 961 | #endif | 
|  | 962 |  | 
|  | 963 | template <typename ResultType, typename T> | 
|  | 964 | ResultType const& get_unchecked(T const& var) | 
|  | 965 | { | 
|  | 966 | return var.template get_unchecked<ResultType>(); | 
|  | 967 | } | 
|  | 968 | } // namespace util | 
|  | 969 | } // namespace mapbox | 
|  | 970 |  | 
|  | 971 | #endif // MAPBOX_UTIL_VARIANT_HPP |