1 #ifndef ANDROID_PDX_RPC_VARIANT_H_ 2 #define ANDROID_PDX_RPC_VARIANT_H_ 3 4 #include <cstdint> 5 #include <tuple> 6 #include <type_traits> 7 8 namespace android { 9 namespace pdx { 10 namespace rpc { 11 12 // Type tag denoting an empty variant. 13 struct EmptyVariant {}; 14 15 namespace detail { 16 17 // Type for matching tagged overloads. 18 template <typename T> 19 struct TypeTag {}; 20 21 // Determines the type of the I-th element of Types.... 22 template <std::size_t I, typename... Types> 23 using TypeForIndex = std::tuple_element_t<I, std::tuple<Types...>>; 24 25 // Determines the type tag for the I-th element of Types.... 26 template <std::size_t I, typename... Types> 27 using TypeTagForIndex = TypeTag<TypeForIndex<I, Types...>>; 28 29 // Enable if T(Args...) is well formed. 30 template <typename R, typename T, typename... Args> 31 using EnableIfConstructible = 32 typename std::enable_if<std::is_constructible<T, Args...>::value, R>::type; 33 // Enable if T(Args...) is not well formed. 34 template <typename R, typename T, typename... Args> 35 using EnableIfNotConstructible = 36 typename std::enable_if<!std::is_constructible<T, Args...>::value, R>::type; 37 38 // Determines whether T is an element of Types...; 39 template <typename... Types> 40 struct HasType : std::false_type {}; 41 template <typename T, typename U> 42 struct HasType<T, U> : std::is_same<std::decay_t<T>, std::decay_t<U>> {}; 43 template <typename T, typename First, typename... Rest> 44 struct HasType<T, First, Rest...> 45 : std::integral_constant<bool, HasType<T, First>::value || 46 HasType<T, Rest...>::value> {}; 47 48 // Defines set operations on a set of Types... 49 template <typename... Types> 50 struct Set { 51 // Default specialization catches the empty set, which is always a subset. 52 template <typename...> 53 struct IsSubset : std::true_type {}; 54 template <typename T> 55 struct IsSubset<T> : HasType<T, Types...> {}; 56 template <typename First, typename... Rest> 57 struct IsSubset<First, Rest...> 58 : std::integral_constant<bool, IsSubset<First>::value && 59 IsSubset<Rest...>::value> {}; 60 }; 61 62 // Determines the number of elements of Types... that are constructible from 63 // From. 64 template <typename... Types> 65 struct ConstructibleCount; 66 template <typename From, typename To> 67 struct ConstructibleCount<From, To> 68 : std::integral_constant<std::size_t, 69 std::is_constructible<To, From>::value> {}; 70 template <typename From, typename First, typename... Rest> 71 struct ConstructibleCount<From, First, Rest...> 72 : std::integral_constant<std::size_t, 73 std::is_constructible<First, From>::value + 74 ConstructibleCount<From, Rest...>::value> {}; 75 76 // Enable if T is an element of Types... 77 template <typename R, typename T, typename... Types> 78 using EnableIfElement = 79 typename std::enable_if<HasType<T, Types...>::value, R>::type; 80 // Enable if T is not an element of Types... 81 template <typename R, typename T, typename... Types> 82 using EnableIfNotElement = 83 typename std::enable_if<!HasType<T, Types...>::value, R>::type; 84 85 // Enable if T is convertible to an element of Types... T is considered 86 // convertible IIF a single element of Types... is assignable from T and T is 87 // not a direct element of Types... 88 template <typename R, typename T, typename... Types> 89 using EnableIfConvertible = 90 typename std::enable_if<!HasType<T, Types...>::value && 91 ConstructibleCount<T, Types...>::value == 1, 92 R>::type; 93 94 // Enable if T is assignable to an element of Types... T is considered 95 // assignable IFF a single element of Types... is constructible from T or T is a 96 // direct element of Types.... Note that T is REQUIRED to be an element of 97 // Types... when multiple elements are constructible from T to prevent ambiguity 98 // in conversion. 99 template <typename R, typename T, typename... Types> 100 using EnableIfAssignable = 101 typename std::enable_if<HasType<T, Types...>::value || 102 ConstructibleCount<T, Types...>::value == 1, 103 R>::type; 104 105 // Selects a type for SFINAE constructor selection. 106 template <bool CondA, typename SelectA, typename SelectB> 107 using Select = std::conditional_t<CondA, SelectA, SelectB>; 108 109 // Recursive union type. 110 template <typename... Types> 111 union Union; 112 113 // Specialization handling a singular type, terminating template recursion. 114 template <typename Type> 115 union Union<Type> { 116 Union() {} 117 ~Union() {} 118 119 template <typename T> 120 Union(std::int32_t index, std::int32_t* index_out, TypeTag<Type>, T&& value) 121 : first_(std::forward<T>(value)) { 122 *index_out = index; 123 } 124 template <typename T, typename = EnableIfAssignable<void, T, Type>> 125 Union(std::int32_t index, std::int32_t* index_out, T&& value) 126 : first_(std::forward<T>(value)) { 127 *index_out = index; 128 } 129 130 Type& get(TypeTag<Type>) { return first_; } 131 const Type& get(TypeTag<Type>) const { return first_; } 132 EmptyVariant get(TypeTag<EmptyVariant>) const { return {}; } 133 constexpr std::int32_t index(TypeTag<Type>) const { return 0; } 134 135 template <typename... Args> 136 std::int32_t Construct(TypeTag<Type>, Args&&... args) { 137 new (&first_) Type(std::forward<Args>(args)...); 138 return 0; 139 } 140 template <typename... Args> 141 EnableIfConstructible<std::int32_t, Type, Args...> Construct(Args&&... args) { 142 new (&first_) Type(std::forward<Args>(args)...); 143 return 0; 144 } 145 146 void Destruct(std::int32_t target_index) { 147 if (target_index == index(TypeTag<Type>{})) { 148 (&get(TypeTag<Type>{}))->~Type(); 149 } 150 } 151 152 template <typename T> 153 bool Assign(TypeTag<Type>, std::int32_t target_index, T&& value) { 154 if (target_index == 0) { 155 first_ = std::forward<T>(value); 156 return true; 157 } else { 158 return false; 159 } 160 } 161 template <typename T> 162 EnableIfConstructible<bool, Type, T> Assign(std::int32_t target_index, 163 T&& value) { 164 if (target_index == 0) { 165 first_ = std::forward<T>(value); 166 return true; 167 } else { 168 return false; 169 } 170 } 171 template <typename T> 172 EnableIfNotConstructible<bool, Type, T> Assign(std::int32_t /*target_index*/, 173 T&& /*value*/) { 174 return false; 175 } 176 177 template <typename Op> 178 decltype(auto) Visit(std::int32_t target_index, Op&& op) { 179 if (target_index == index(TypeTag<Type>{})) 180 return std::forward<Op>(op)(get(TypeTag<Type>{})); 181 else 182 return std::forward<Op>(op)(get(TypeTag<EmptyVariant>{})); 183 } 184 template <typename Op> 185 decltype(auto) Visit(std::int32_t target_index, Op&& op) const { 186 if (target_index == index(TypeTag<Type>{})) 187 return std::forward<Op>(op)(get(TypeTag<Type>{})); 188 else 189 return std::forward<Op>(op)(get(TypeTag<EmptyVariant>{})); 190 } 191 192 template <typename... Args> 193 bool Become(std::int32_t target_index, Args&&... args) { 194 if (target_index == index(TypeTag<Type>{})) { 195 Construct(TypeTag<Type>{}, std::forward<Args>(args)...); 196 return true; 197 } else { 198 return false; 199 } 200 } 201 202 private: 203 Type first_; 204 }; 205 206 // Specialization that recursively unions types from the paramater pack. 207 template <typename First, typename... Rest> 208 union Union<First, Rest...> { 209 Union() {} 210 ~Union() {} 211 212 template <typename T> 213 Union(std::int32_t index, std::int32_t* index_out, TypeTag<First>, T&& value) 214 : first_(std::forward<T>(value)) { 215 *index_out = index; 216 } 217 template <typename T, typename U> 218 Union(std::int32_t index, std::int32_t* index_out, TypeTag<T>, U&& value) 219 : rest_(index + 1, index_out, TypeTag<T>{}, std::forward<U>(value)) {} 220 221 struct FirstType {}; 222 struct RestType {}; 223 template <typename T> 224 using SelectConstructor = 225 Select<ConstructibleCount<T, First>::value == 1, FirstType, RestType>; 226 227 template <typename T> 228 Union(std::int32_t index, std::int32_t* index_out, T&& value) 229 : Union(index, index_out, std::forward<T>(value), 230 SelectConstructor<T>{}) {} 231 232 template <typename T> 233 Union(std::int32_t index, std::int32_t* index_out, T&& value, FirstType) 234 : first_(std::forward<T>(value)) { 235 *index_out = index; 236 } 237 template <typename T> 238 Union(std::int32_t index, std::int32_t* index_out, T&& value, RestType) 239 : rest_(index + 1, index_out, std::forward<T>(value)) {} 240 241 First& get(TypeTag<First>) { return first_; } 242 const First& get(TypeTag<First>) const { return first_; } 243 constexpr std::int32_t index(TypeTag<First>) const { return 0; } 244 245 template <typename T> 246 T& get(TypeTag<T>) { 247 return rest_.template get(TypeTag<T>{}); 248 } 249 template <typename T> 250 const T& get(TypeTag<T>) const { 251 return rest_.template get(TypeTag<T>{}); 252 } 253 template <typename T> 254 constexpr std::int32_t index(TypeTag<T>) const { 255 return 1 + rest_.template index(TypeTag<T>{}); 256 } 257 258 template <typename... Args> 259 std::int32_t Construct(TypeTag<First>, Args&&... args) { 260 new (&first_) First(std::forward<Args>(args)...); 261 return 0; 262 } 263 template <typename T, typename... Args> 264 std::int32_t Construct(TypeTag<T>, Args&&... args) { 265 return 1 + 266 rest_.template Construct(TypeTag<T>{}, std::forward<Args>(args)...); 267 } 268 269 template <typename... Args> 270 EnableIfConstructible<std::int32_t, First, Args...> Construct( 271 Args&&... args) { 272 new (&first_) First(std::forward<Args>(args)...); 273 return 0; 274 } 275 template <typename... Args> 276 EnableIfNotConstructible<std::int32_t, First, Args...> Construct( 277 Args&&... args) { 278 return 1 + rest_.template Construct(std::forward<Args>(args)...); 279 } 280 281 void Destruct(std::int32_t target_index) { 282 if (target_index == index(TypeTag<First>{})) { 283 (get(TypeTag<First>{})).~First(); 284 } else { 285 rest_.Destruct(target_index - 1); 286 } 287 } 288 289 template <typename T> 290 bool Assign(TypeTag<First>, std::int32_t target_index, T&& value) { 291 if (target_index == 0) { 292 first_ = std::forward<T>(value); 293 return true; 294 } else { 295 return false; 296 } 297 } 298 template <typename T, typename U> 299 bool Assign(TypeTag<T>, std::int32_t target_index, U&& value) { 300 return rest_.Assign(TypeTag<T>{}, target_index - 1, std::forward<U>(value)); 301 } 302 template <typename T> 303 EnableIfConstructible<bool, First, T> Assign(std::int32_t target_index, 304 T&& value) { 305 if (target_index == 0) { 306 first_ = std::forward<T>(value); 307 return true; 308 } else { 309 return rest_.Assign(target_index - 1, std::forward<T>(value)); 310 } 311 } 312 template <typename T> 313 EnableIfNotConstructible<bool, First, T> Assign(std::int32_t target_index, 314 T&& value) { 315 return rest_.Assign(target_index - 1, std::forward<T>(value)); 316 } 317 318 // Recursively traverses the union and calls Op on the active value when the 319 // active type is found. If the union is empty Op is called on EmptyVariant. 320 // TODO(eieio): This could be refactored into an array or jump table. It's 321 // unclear whether this would be more efficient for practical variant arity. 322 template <typename Op> 323 decltype(auto) Visit(std::int32_t target_index, Op&& op) { 324 if (target_index == index(TypeTag<First>{})) 325 return std::forward<Op>(op)(get(TypeTag<First>{})); 326 else 327 return rest_.Visit(target_index - 1, std::forward<Op>(op)); 328 } 329 template <typename Op> 330 decltype(auto) Visit(std::int32_t target_index, Op&& op) const { 331 if (target_index == index(TypeTag<First>{})) 332 return std::forward<Op>(op)(get(TypeTag<First>{})); 333 else 334 return rest_.Visit(target_index - 1, std::forward<Op>(op)); 335 } 336 337 template <typename... Args> 338 bool Become(std::int32_t target_index, Args&&... args) { 339 if (target_index == index(TypeTag<First>{})) { 340 Construct(TypeTag<First>{}, std::forward<Args>(args)...); 341 return true; 342 } else { 343 return rest_.Become(target_index - 1, std::forward<Args>(args)...); 344 } 345 } 346 347 private: 348 First first_; 349 Union<Rest...> rest_; 350 }; 351 352 } // namespace detail 353 354 template <typename... Types> 355 class Variant { 356 private: 357 // Convenience types. 358 template <typename T> 359 using TypeTag = detail::TypeTag<T>; 360 template <typename T> 361 using DecayedTypeTag = TypeTag<std::decay_t<T>>; 362 template <std::size_t I> 363 using TypeForIndex = detail::TypeForIndex<I, Types...>; 364 template <std::size_t I> 365 using TypeTagForIndex = detail::TypeTagForIndex<I, Types...>; 366 template <typename T> 367 using HasType = detail::HasType<T, Types...>; 368 template <typename R, typename T> 369 using EnableIfElement = detail::EnableIfElement<R, T, Types...>; 370 template <typename R, typename T> 371 using EnableIfConvertible = detail::EnableIfConvertible<R, T, Types...>; 372 template <typename R, typename T> 373 using EnableIfAssignable = detail::EnableIfAssignable<R, T, Types...>; 374 375 struct Direct {}; 376 struct Convert {}; 377 template <typename T> 378 using SelectConstructor = detail::Select<HasType<T>::value, Direct, Convert>; 379 380 // Constructs by type tag when T is an direct element of Types... 381 template <typename T> 382 explicit Variant(T&& value, Direct) 383 : value_(0, &index_, DecayedTypeTag<T>{}, std::forward<T>(value)) {} 384 // Conversion constructor when T is not a direct element of Types... 385 template <typename T> 386 explicit Variant(T&& value, Convert) 387 : value_(0, &index_, std::forward<T>(value)) {} 388 389 public: 390 // Variants are default construcible, regardless of whether the elements are 391 // default constructible. Default consruction yields an empty Variant. 392 Variant() {} 393 explicit Variant(EmptyVariant) {} 394 ~Variant() { Destruct(); } 395 396 // Copy and move construction from Variant types. Each element of OtherTypes 397 // must be convertible to an element of Types. 398 template <typename... OtherTypes> 399 explicit Variant(const Variant<OtherTypes...>& other) { 400 other.Visit([this](const auto& value) { Construct(value); }); 401 } 402 template <typename... OtherTypes> 403 explicit Variant(Variant<OtherTypes...>&& other) { 404 other.Visit([this](auto&& value) { Construct(std::move(value)); }); 405 } 406 407 // Construction from non-Variant types. 408 template <typename T, typename = EnableIfAssignable<void, T>> 409 explicit Variant(T&& value) 410 : Variant(std::forward<T>(value), SelectConstructor<T>{}) {} 411 412 // Performs assignment from type T belonging to Types. This overload takes 413 // priority to prevent implicit conversion in cases where T is implicitly 414 // convertible to multiple elements of Types. 415 template <typename T> 416 EnableIfElement<Variant&, T> operator=(T&& value) { 417 Assign(DecayedTypeTag<T>{}, std::forward<T>(value)); 418 return *this; 419 } 420 421 // Performs assignment from type T not belonging to Types. This overload 422 // matches in cases where conversion is the only viable option. 423 template <typename T> 424 EnableIfConvertible<Variant&, T> operator=(T&& value) { 425 Assign(std::forward<T>(value)); 426 return *this; 427 } 428 429 // Handles assignment from the empty type. This overload supports assignment 430 // in visitors using generic lambdas. 431 Variant& operator=(EmptyVariant) { 432 Assign(EmptyVariant{}); 433 return *this; 434 } 435 436 // Assignment from Variant types. Each element of OtherTypes must be 437 // convertible to an element of Types. Forwards through non-Variant assignment 438 // operators to apply conversion checks. 439 template <typename... OtherTypes> 440 Variant& operator=(const Variant<OtherTypes...>& other) { 441 other.Visit([this](const auto& value) { *this = value; }); 442 return *this; 443 } 444 template <typename... OtherTypes> 445 Variant& operator=(Variant<OtherTypes...>&& other) { 446 other.Visit([this](auto&& value) { *this = std::move(value); }); 447 return *this; 448 } 449 450 // Becomes the target type, constructing a new element from the given 451 // arguments if necessary. No action is taken if the active element is already 452 // the target type. Otherwise the active element is destroyed and replaced by 453 // constructing an element of the new type using |Args|. An invalid target 454 // type index results in an empty Variant. 455 template <typename... Args> 456 void Become(std::int32_t target_index, Args&&... args) { 457 if (target_index != index()) { 458 Destruct(); 459 index_ = value_.Become(target_index, std::forward<Args>(args)...) 460 ? target_index 461 : kEmptyIndex; 462 } 463 } 464 465 // Invokes |Op| on the active element. If the Variant is empty |Op| is invoked 466 // on EmptyVariant. 467 template <typename Op> 468 decltype(auto) Visit(Op&& op) { 469 return value_.Visit(index_, std::forward<Op>(op)); 470 } 471 template <typename Op> 472 decltype(auto) Visit(Op&& op) const { 473 return value_.Visit(index_, std::forward<Op>(op)); 474 } 475 476 // Index returned when the Variant is empty. 477 enum : std::int32_t { kEmptyIndex = -1 }; 478 479 // Returns the index of the given type. 480 template <typename T> 481 constexpr std::int32_t index_of() const { 482 static_assert(HasType<T>::value, "T is not an element type of Variant."); 483 return value_.template index(DecayedTypeTag<T>{}); 484 } 485 486 // Returns the index of the active type. If the Variant is empty -1 is 487 // returned. 488 std::int32_t index() const { return index_; } 489 490 // Returns true if the given type is active, false otherwise. 491 template <typename T> 492 bool is() const { 493 static_assert(HasType<T>::value, "T is not an element type of Variant."); 494 return index() == index_of<T>(); 495 } 496 497 // Returns true if the Variant is empty, false otherwise. 498 bool empty() const { return index() == kEmptyIndex; } 499 500 // Element accessors. Returns a pointer to the active value if the given 501 // type/index is active, otherwise nullptr is returned. 502 template <typename T> 503 T* get() { 504 if (is<T>()) 505 return &value_.template get(DecayedTypeTag<T>{}); 506 else 507 return nullptr; 508 } 509 template <typename T> 510 const T* get() const { 511 if (is<T>()) 512 return &value_.template get(DecayedTypeTag<T>{}); 513 else 514 return nullptr; 515 } 516 template <std::size_t I> 517 TypeForIndex<I>* get() { 518 if (is<TypeForIndex<I>>()) 519 return &value_.template get(TypeTagForIndex<I>{}); 520 else 521 return nullptr; 522 } 523 template <std::size_t I> 524 const TypeForIndex<I>* get() const { 525 if (is<TypeForIndex<I>>()) 526 return &value_.template get(TypeTagForIndex<I>{}); 527 else 528 return nullptr; 529 } 530 531 private: 532 std::int32_t index_ = kEmptyIndex; 533 detail::Union<std::decay_t<Types>...> value_; 534 535 // Constructs an element from the given arguments and sets the Variant to the 536 // resulting type. 537 template <typename... Args> 538 void Construct(Args&&... args) { 539 index_ = value_.template Construct(std::forward<Args>(args)...); 540 } 541 void Construct(EmptyVariant) {} 542 543 // Destroys the active element of the Variant. 544 void Destruct() { value_.Destruct(index_); } 545 546 // Assigns the Variant when non-empty and the current type matches the target 547 // type, otherwise destroys the current value and constructs a element of the 548 // new type. Tagged assignment is used when T is an element of the Variant to 549 // prevent implicit conversion in cases where T is implicitly convertible to 550 // multiple element types. 551 template <typename T, typename U> 552 void Assign(TypeTag<T>, U&& value) { 553 if (!value_.template Assign(TypeTag<T>{}, index_, std::forward<U>(value))) { 554 Destruct(); 555 Construct(TypeTag<T>{}, std::forward<U>(value)); 556 } 557 } 558 template <typename T> 559 void Assign(T&& value) { 560 if (!value_.template Assign(index_, std::forward<T>(value))) { 561 Destruct(); 562 Construct(std::forward<T>(value)); 563 } 564 } 565 // Handles assignment from an empty Variant. 566 void Assign(EmptyVariant) { Destruct(); } 567 }; 568 569 // Utility type to extract/convert values from a variant. This class simplifies 570 // conditional logic to get/move/swap/action values from a variant when one or 571 // more elements are compatible with the destination type. 572 // 573 // Example: 574 // Variant<int, bool, std::string> v(10); 575 // bool bool_value; 576 // if (IfAnyOf<int, bool>::Get(v, &bool_value)) { 577 // DoSomething(bool_value); 578 // } else { 579 // HandleInvalidType(); 580 // } 581 // IfAnyOf<int>::Call(v, [](const auto& value) { DoSomething(value); }); 582 // 583 template <typename... ValidTypes> 584 struct IfAnyOf { 585 // Calls Op on the underlying value of the variant and returns true when the 586 // variant is a valid type, otherwise does nothing and returns false. 587 template <typename Op, typename... Types> 588 static bool Call(Variant<Types...>* variant, Op&& op) { 589 static_assert( 590 detail::Set<Types...>::template IsSubset<ValidTypes...>::value, 591 "ValidTypes may only contain element types from the Variant."); 592 return variant->Visit(CallOp<Op>{std::forward<Op>(op)}); 593 } 594 template <typename Op, typename... Types> 595 static bool Call(const Variant<Types...>* variant, Op&& op) { 596 static_assert( 597 detail::Set<Types...>::template IsSubset<ValidTypes...>::value, 598 "ValidTypes may only contain element types from the Variant."); 599 return variant->Visit(CallOp<Op>{std::forward<Op>(op)}); 600 } 601 602 // Gets/converts the underlying value of the variant to type T and returns 603 // true when the variant is a valid type, otherwise does nothing and returns 604 // false. 605 template <typename T, typename... Types> 606 static bool Get(const Variant<Types...>* variant, T* value_out) { 607 return Call(variant, 608 [value_out](const auto& value) { *value_out = value; }); 609 } 610 611 // Moves the underlying value of the variant and returns true when the variant 612 // is a valid type, otherwise does nothing and returns false. 613 template <typename T, typename... Types> 614 static bool Take(Variant<Types...>* variant, T* value_out) { 615 return Call(variant, 616 [value_out](auto&& value) { *value_out = std::move(value); }); 617 } 618 619 // Swaps the underlying value of the variant with |*value_out| and returns 620 // true when the variant is a valid type, otherwise does nothing and returns 621 // false. 622 template <typename T, typename... Types> 623 static bool Swap(Variant<Types...>* variant, T* value_out) { 624 return Call(variant, 625 [value_out](auto&& value) { std::swap(*value_out, value); }); 626 } 627 628 private: 629 template <typename Op> 630 struct CallOp { 631 Op&& op; 632 template <typename U> 633 detail::EnableIfNotElement<bool, U, ValidTypes...> operator()(U&&) { 634 return false; 635 } 636 template <typename U> 637 detail::EnableIfElement<bool, U, ValidTypes...> operator()(const U& value) { 638 std::forward<Op>(op)(value); 639 return true; 640 } 641 template <typename U> 642 detail::EnableIfElement<bool, U, ValidTypes...> operator()(U&& value) { 643 std::forward<Op>(op)(std::forward<U>(value)); 644 return true; 645 } 646 }; 647 }; 648 649 } // namespace rpc 650 } // namespace pdx 651 } // namespace android 652 653 // Overloads of std::get<T> and std::get<I> for android::pdx::rpc::Variant. 654 namespace std { 655 656 template <typename T, typename... Types> 657 inline T& get(::android::pdx::rpc::Variant<Types...>& v) { 658 return *v.template get<T>(); 659 } 660 template <typename T, typename... Types> 661 inline T&& get(::android::pdx::rpc::Variant<Types...>&& v) { 662 return std::move(*v.template get<T>()); 663 } 664 template <typename T, typename... Types> 665 inline const T& get(const ::android::pdx::rpc::Variant<Types...>& v) { 666 return *v.template get<T>(); 667 } 668 template <std::size_t I, typename... Types> 669 inline ::android::pdx::rpc::detail::TypeForIndex<I, Types...>& get( 670 ::android::pdx::rpc::Variant<Types...>& v) { 671 return *v.template get<I>(); 672 } 673 template <std::size_t I, typename... Types> 674 inline ::android::pdx::rpc::detail::TypeForIndex<I, Types...>&& get( 675 ::android::pdx::rpc::Variant<Types...>&& v) { 676 return std::move(*v.template get<I>()); 677 } 678 template <std::size_t I, typename... Types> 679 inline const ::android::pdx::rpc::detail::TypeForIndex<I, Types...>& get( 680 const ::android::pdx::rpc::Variant<Types...>& v) { 681 return *v.template get<I>(); 682 } 683 684 } // namespace std 685 686 #endif // ANDROID_PDX_RPC_VARIANT_H_ 687