webdriver: Implement Fullscreen command support (#100)
[gecko.git] / mfbt / Variant.h
blob9e90168a6acf9b9c4067f8bc65c2ecc5ccc39e9d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* A template class for tagged unions. */
9 #include <new>
10 #include <stdint.h>
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Move.h"
14 #include "mozilla/OperatorNewExtensions.h"
15 #include "mozilla/TemplateLib.h"
16 #include "mozilla/TypeTraits.h"
18 #ifndef mozilla_Variant_h
19 #define mozilla_Variant_h
21 namespace IPC {
22 template <typename T> struct ParamTraits;
23 } // namespace IPC
25 namespace mozilla {
27 template<typename... Ts>
28 class Variant;
30 namespace detail {
32 // Nth<N, types...>::Type is the Nth type (0-based) in the list of types Ts.
33 template<size_t N, typename... Ts>
34 struct Nth;
36 template<typename T, typename... Ts>
37 struct Nth<0, T, Ts...>
39 using Type = T;
42 template<size_t N, typename T, typename... Ts>
43 struct Nth<N, T, Ts...>
45 using Type = typename Nth<N - 1, Ts...>::Type;
48 /// SelectVariantTypeHelper is used in the implementation of SelectVariantType.
49 template<typename T, typename... Variants>
50 struct SelectVariantTypeHelper;
52 template<typename T>
53 struct SelectVariantTypeHelper<T>
55 static constexpr size_t count = 0;
58 template<typename T, typename... Variants>
59 struct SelectVariantTypeHelper<T, T, Variants...>
61 typedef T Type;
62 static constexpr size_t count = 1 + SelectVariantTypeHelper<T, Variants...>::count;
65 template<typename T, typename... Variants>
66 struct SelectVariantTypeHelper<T, const T, Variants...>
68 typedef const T Type;
69 static constexpr size_t count = 1 + SelectVariantTypeHelper<T, Variants...>::count;
72 template<typename T, typename... Variants>
73 struct SelectVariantTypeHelper<T, const T&, Variants...>
75 typedef const T& Type;
76 static constexpr size_t count = 1 + SelectVariantTypeHelper<T, Variants...>::count;
79 template<typename T, typename... Variants>
80 struct SelectVariantTypeHelper<T, T&&, Variants...>
82 typedef T&& Type;
83 static constexpr size_t count = 1 + SelectVariantTypeHelper<T, Variants...>::count;
86 template<typename T, typename Head, typename... Variants>
87 struct SelectVariantTypeHelper<T, Head, Variants...>
88 : public SelectVariantTypeHelper<T, Variants...>
89 { };
91 /**
92 * SelectVariantType takes a type T and a list of variant types Variants and
93 * yields a type Type, selected from Variants, that can store a value of type T
94 * or a reference to type T. If no such type was found, Type is not defined.
95 * SelectVariantType also has a `count` member that contains the total number of
96 * selectable types (which will be used to check that a requested type is not
97 * ambiguously present twice.)
99 template <typename T, typename... Variants>
100 struct SelectVariantType
101 : public SelectVariantTypeHelper<typename RemoveConst<typename RemoveReference<T>::Type>::Type,
102 Variants...>
103 { };
105 // Compute a fast, compact type that can be used to hold integral values that
106 // distinctly map to every type in Ts.
107 template<typename... Ts>
108 struct VariantTag
110 private:
111 static const size_t TypeCount = sizeof...(Ts);
113 public:
114 using Type =
115 typename Conditional<TypeCount < 3,
116 bool,
117 typename Conditional<TypeCount < (1 << 8),
118 uint_fast8_t,
119 size_t // stop caring past a certain point :-)
120 >::Type
121 >::Type;
124 // TagHelper gets the given sentinel tag value for the given type T. This has to
125 // be split out from VariantImplementation because you can't nest a partial
126 // template specialization within a template class.
128 template<typename Tag, size_t N, typename T, typename U, typename Next, bool isMatch>
129 struct TagHelper;
131 // In the case where T != U, we continue recursion.
132 template<typename Tag, size_t N, typename T, typename U, typename Next>
133 struct TagHelper<Tag, N, T, U, Next, false>
135 static Tag tag() { return Next::template tag<U>(); }
138 // In the case where T == U, return the tag number.
139 template<typename Tag, size_t N, typename T, typename U, typename Next>
140 struct TagHelper<Tag, N, T, U, Next, true>
142 static Tag tag() { return Tag(N); }
145 // The VariantImplementation template provides the guts of mozilla::Variant. We
146 // create a VariantImplementation for each T in Ts... which handles
147 // construction, destruction, etc for when the Variant's type is T. If the
148 // Variant's type isn't T, it punts the request on to the next
149 // VariantImplementation.
151 template<typename Tag, size_t N, typename... Ts>
152 struct VariantImplementation;
154 // The singly typed Variant / recursion base case.
155 template<typename Tag, size_t N, typename T>
156 struct VariantImplementation<Tag, N, T>
158 template<typename U>
159 static Tag tag() {
160 static_assert(mozilla::IsSame<T, U>::value,
161 "mozilla::Variant: tag: bad type!");
162 return Tag(N);
165 template<typename Variant>
166 static void copyConstruct(void* aLhs, const Variant& aRhs) {
167 ::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
170 template<typename Variant>
171 static void moveConstruct(void* aLhs, Variant&& aRhs) {
172 ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
175 template<typename Variant>
176 static void destroy(Variant& aV) {
177 aV.template as<N>().~T();
180 template<typename Variant>
181 static bool
182 equal(const Variant& aLhs, const Variant& aRhs) {
183 return aLhs.template as<N>() == aRhs.template as<N>();
186 template<typename Matcher, typename ConcreteVariant>
187 static auto
188 match(Matcher&& aMatcher, ConcreteVariant& aV)
189 -> decltype(aMatcher.match(aV.template as<N>()))
191 return aMatcher.match(aV.template as<N>());
195 // VariantImplementation for some variant type T.
196 template<typename Tag, size_t N, typename T, typename... Ts>
197 struct VariantImplementation<Tag, N, T, Ts...>
199 // The next recursive VariantImplementation.
200 using Next = VariantImplementation<Tag, N + 1, Ts...>;
202 template<typename U>
203 static Tag tag() {
204 return TagHelper<Tag, N, T, U, Next, IsSame<T, U>::value>::tag();
207 template<typename Variant>
208 static void copyConstruct(void* aLhs, const Variant& aRhs) {
209 if (aRhs.template is<N>()) {
210 ::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
211 } else {
212 Next::copyConstruct(aLhs, aRhs);
216 template<typename Variant>
217 static void moveConstruct(void* aLhs, Variant&& aRhs) {
218 if (aRhs.template is<N>()) {
219 ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
220 } else {
221 Next::moveConstruct(aLhs, Move(aRhs));
225 template<typename Variant>
226 static void destroy(Variant& aV) {
227 if (aV.template is<N>()) {
228 aV.template as<N>().~T();
229 } else {
230 Next::destroy(aV);
234 template<typename Variant>
235 static bool equal(const Variant& aLhs, const Variant& aRhs) {
236 if (aLhs.template is<N>()) {
237 MOZ_ASSERT(aRhs.template is<N>());
238 return aLhs.template as<N>() == aRhs.template as<N>();
239 } else {
240 return Next::equal(aLhs, aRhs);
244 template<typename Matcher, typename ConcreteVariant>
245 static auto
246 match(Matcher&& aMatcher, ConcreteVariant& aV)
247 -> decltype(aMatcher.match(aV.template as<N>()))
249 if (aV.template is<N>()) {
250 return aMatcher.match(aV.template as<N>());
251 } else {
252 // If you're seeing compilation errors here like "no matching
253 // function for call to 'match'" then that means that the
254 // Matcher doesn't exhaust all variant types. There must exist a
255 // Matcher::match(T&) for every variant type T.
257 // If you're seeing compilation errors here like "cannot
258 // initialize return object of type <...> with an rvalue of type
259 // <...>" then that means that the Matcher::match(T&) overloads
260 // are returning different types. They must all return the same
261 // Matcher::ReturnType type.
262 return Next::match(aMatcher, aV);
268 * AsVariantTemporary stores a value of type T to allow construction of a
269 * Variant value via type inference. Because T is copied and there's no
270 * guarantee that the copy can be elided, AsVariantTemporary is best used with
271 * primitive or very small types.
273 template <typename T>
274 struct AsVariantTemporary
276 explicit AsVariantTemporary(const T& aValue)
277 : mValue(aValue)
280 template<typename U>
281 explicit AsVariantTemporary(U&& aValue)
282 : mValue(Forward<U>(aValue))
285 AsVariantTemporary(const AsVariantTemporary& aOther)
286 : mValue(aOther.mValue)
289 AsVariantTemporary(AsVariantTemporary&& aOther)
290 : mValue(Move(aOther.mValue))
293 AsVariantTemporary() = delete;
294 void operator=(const AsVariantTemporary&) = delete;
295 void operator=(AsVariantTemporary&&) = delete;
297 typename RemoveConst<typename RemoveReference<T>::Type>::Type mValue;
300 } // namespace detail
302 // Used to unambiguously specify one of the Variant's type.
303 template<typename T> struct VariantType { using Type = T; };
305 // Used to specify one of the Variant's type by index.
306 template<size_t N> struct VariantIndex { static constexpr size_t index = N; };
309 * # mozilla::Variant
311 * A variant / tagged union / heterogenous disjoint union / sum-type template
312 * class. Similar in concept to (but not derived from) `boost::variant`.
314 * Sometimes, you may wish to use a C union with non-POD types. However, this is
315 * forbidden in C++ because it is not clear which type in the union should have
316 * its constructor and destructor run on creation and deletion
317 * respectively. This is the problem that `mozilla::Variant` solves.
319 * ## Usage
321 * A `mozilla::Variant` instance is constructed (via move or copy) from one of
322 * its variant types (ignoring const and references). It does *not* support
323 * construction from subclasses of variant types or types that coerce to one of
324 * the variant types.
326 * Variant<char, uint32_t> v1('a');
327 * Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>());
328 * Variant<bool, char> v3(VariantType<char>, 0); // disambiguation needed
329 * Variant<int, int> v4(VariantIndex<1>, 0); // 2nd int
331 * Because specifying the full type of a Variant value is often verbose,
332 * there are two easier ways to construct values:
334 * A. AsVariant() can be used to construct a Variant value using type inference
335 * in contexts such as expressions or when returning values from functions.
336 * Because AsVariant() must copy or move the value into a temporary and this
337 * cannot necessarily be elided by the compiler, it's mostly appropriate only
338 * for use with primitive or very small types.
340 * Variant<char, uint32_t> Foo() { return AsVariant('x'); }
341 * // ...
342 * Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x').
344 * B. Brace-construction with VariantType or VariantIndex; this also allows
345 * in-place construction with any number of arguments.
347 * struct AB { AB(int, int){...} };
348 * static Variant<AB, bool> foo()
350 * return {VariantIndex<0>{}, 1, 2};
352 * // ...
353 * Variant<AB, bool> v0 = Foo(); // v0 holds AB(1,2).
355 * All access to the contained value goes through type-safe accessors.
356 * Either the stored type, or the type index may be provided.
358 * void
359 * Foo(Variant<A, B, C> v)
361 * if (v.is<A>()) {
362 * A& ref = v.as<A>();
363 * ...
364 * } else (v.is<1>()) { // Instead of v.is<B>.
365 * ...
366 * } else {
367 * ...
371 * In some situation, a Variant may be constructed from templated types, in
372 * which case it is possible that the same type could be given multiple times by
373 * an external developer. Or seemingly-different types could be aliases.
374 * In this case, repeated types can only be accessed through their index, to
375 * prevent ambiguous access by type.
377 * // Bad!
378 * template <typename T>
379 * struct ResultOrError
381 * Variant<T, int> m;
382 * ResultOrError() : m(int(0)) {} // Error '0' by default
383 * ResultOrError(const T& r) : m(r) {}
384 * bool IsResult() const { return m.is<T>(); }
385 * bool IsError() const { return m.is<int>(); }
386 * };
387 * // Now instantiante with the result being an int too:
388 * ResultOrError<int> myResult(123); // Fail!
389 * // In Variant<int, int>, which 'int' are we refering to, from inside
390 * // ResultOrError functions?
392 * // Good!
393 * template <typename T>
394 * struct ResultOrError
396 * Variant<T, int> m;
397 * ResultOrError() : m(VariantIndex<1>{}, 0) {} // Error '0' by default
398 * ResultOrError(const T& r) : m(VariantIndex<0>{}, r) {}
399 * bool IsResult() const { return m.is<0>(); } // 0 -> T
400 * bool IsError() const { return m.is<1>(); } // 1 -> int
401 * };
402 * // Now instantiante with the result being an int too:
403 * ResultOrError<int> myResult(123); // It now works!
405 * Attempting to use the contained value as type `T1` when the `Variant`
406 * instance contains a value of type `T2` causes an assertion failure.
408 * A a;
409 * Variant<A, B, C> v(a);
410 * v.as<B>(); // <--- Assertion failure!
412 * Trying to use a `Variant<Ts...>` instance as some type `U` that is not a
413 * member of the set of `Ts...` is a compiler error.
415 * A a;
416 * Variant<A, B, C> v(a);
417 * v.as<SomeRandomType>(); // <--- Compiler error!
419 * Additionally, you can turn a `Variant` that `is<T>` into a `T` by moving it
420 * out of the containing `Variant` instance with the `extract<T>` method:
422 * Variant<UniquePtr<A>, B, C> v(MakeUnique<A>());
423 * auto ptr = v.extract<UniquePtr<A>>();
425 * Finally, you can exhaustively match on the contained variant and branch into
426 * different code paths depending on which type is contained. This is preferred
427 * to manually checking every variant type T with is<T>() because it provides
428 * compile-time checking that you handled every type, rather than runtime
429 * assertion failures.
431 * // Bad!
432 * char* foo(Variant<A, B, C, D>& v) {
433 * if (v.is<A>()) {
434 * return ...;
435 * } else if (v.is<B>()) {
436 * return ...;
437 * } else {
438 * return doSomething(v.as<C>()); // Forgot about case D!
442 * // Good!
443 * struct FooMatcher
445 * // The return type of all matchers must be identical.
446 * char* match(A& a) { ... }
447 * char* match(B& b) { ... }
448 * char* match(C& c) { ... }
449 * char* match(D& d) { ... } // Compile-time error to forget D!
451 * char* foo(Variant<A, B, C, D>& v) {
452 * return v.match(FooMatcher());
455 * ## Examples
457 * A tree is either an empty leaf, or a node with a value and two children:
459 * struct Leaf { };
461 * template<typename T>
462 * struct Node
464 * T value;
465 * Tree<T>* left;
466 * Tree<T>* right;
467 * };
469 * template<typename T>
470 * using Tree = Variant<Leaf, Node<T>>;
472 * A copy-on-write string is either a non-owning reference to some existing
473 * string, or an owning reference to our copy:
475 * class CopyOnWriteString
477 * Variant<const char*, UniquePtr<char[]>> string;
479 * ...
480 * };
482 * Because Variant must be aligned suitable to hold any value stored within it,
483 * and because |alignas| requirements don't affect platform ABI with respect to
484 * how parameters are laid out in memory, Variant can't be used as the type of a
485 * function parameter. Pass Variant to functions by pointer or reference
486 * instead.
488 template<typename... Ts>
489 class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant
491 friend struct IPC::ParamTraits<mozilla::Variant<Ts...>>;
493 using Tag = typename detail::VariantTag<Ts...>::Type;
494 using Impl = detail::VariantImplementation<Tag, 0, Ts...>;
496 static constexpr size_t RawDataAlignment = tl::Max<alignof(Ts)...>::value;
497 static constexpr size_t RawDataSize = tl::Max<sizeof(Ts)...>::value;
499 // Raw storage for the contained variant value.
500 alignas(RawDataAlignment) unsigned char rawData[RawDataSize];
502 // Each type is given a unique tag value that lets us keep track of the
503 // contained variant value's type.
504 Tag tag;
506 // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
507 // -Werror compile error) to reinterpret_cast<> |rawData| to |T*|, even
508 // through |void*|. Placing the latter cast in these separate functions
509 // breaks the chain such that affected GCC versions no longer warn/error.
510 void* ptr() {
511 return rawData;
514 const void* ptr() const {
515 return rawData;
518 public:
519 /** Perfect forwarding construction for some variant type T. */
520 template<typename RefT,
521 // RefT captures both const& as well as && (as intended, to support
522 // perfect forwarding), so we have to remove those qualifiers here
523 // when ensuring that T is a variant of this type, and getting T's
524 // tag, etc.
525 typename T = typename detail::SelectVariantType<RefT, Ts...>::Type>
526 explicit Variant(RefT&& aT)
527 : tag(Impl::template tag<T>())
529 static_assert(detail::SelectVariantType<RefT, Ts...>::count == 1,
530 "Variant can only be selected by type if that type is unique");
531 ::new (KnownNotNull, ptr()) T(Forward<RefT>(aT));
535 * Perfect forwarding construction for some variant type T, by
536 * explicitly giving the type.
537 * This is necessary to construct from any number of arguments,
538 * or to convert from a type that is not in the Variant's type list.
540 template<typename T, typename... Args>
541 MOZ_IMPLICIT Variant(const VariantType<T>&, Args&&... aTs)
542 : tag(Impl::template tag<T>())
544 ::new (KnownNotNull, ptr()) T(Forward<Args>(aTs)...);
548 * Perfect forwarding construction for some variant type T, by
549 * explicitly giving the type index.
550 * This is necessary to construct from any number of arguments,
551 * or to convert from a type that is not in the Variant's type list,
552 * or to construct a type that is present more than once in the Variant.
554 template<size_t N, typename... Args>
555 MOZ_IMPLICIT Variant(const VariantIndex<N>&, Args&&... aTs)
556 : tag(N)
558 using T = typename detail::Nth<N, Ts...>::Type;
559 ::new (KnownNotNull, ptr()) T(Forward<Args>(aTs)...);
563 * Constructs this Variant from an AsVariantTemporary<T> such that T can be
564 * stored in one of the types allowable in this Variant. This is used in the
565 * implementation of AsVariant().
567 template<typename RefT>
568 MOZ_IMPLICIT Variant(detail::AsVariantTemporary<RefT>&& aValue)
569 : tag(Impl::template tag<typename detail::SelectVariantType<RefT, Ts...>::Type>())
571 using T = typename detail::SelectVariantType<RefT, Ts...>::Type;
572 static_assert(detail::SelectVariantType<RefT, Ts...>::count == 1,
573 "Variant can only be selected by type if that type is unique");
574 ::new (KnownNotNull, ptr()) T(Move(aValue.mValue));
577 /** Copy construction. */
578 Variant(const Variant& aRhs)
579 : tag(aRhs.tag)
581 Impl::copyConstruct(ptr(), aRhs);
584 /** Move construction. */
585 Variant(Variant&& aRhs)
586 : tag(aRhs.tag)
588 Impl::moveConstruct(ptr(), Move(aRhs));
591 /** Copy assignment. */
592 Variant& operator=(const Variant& aRhs) {
593 MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
594 this->~Variant();
595 ::new (KnownNotNull, this) Variant(aRhs);
596 return *this;
599 /** Move assignment. */
600 Variant& operator=(Variant&& aRhs) {
601 MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
602 this->~Variant();
603 ::new (KnownNotNull, this) Variant(Move(aRhs));
604 return *this;
607 /** Move assignment from AsVariant(). */
608 template<typename T>
609 Variant& operator=(detail::AsVariantTemporary<T>&& aValue)
611 static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
612 "Variant can only be selected by type if that type is unique");
613 this->~Variant();
614 ::new (KnownNotNull, this) Variant(Move(aValue));
615 return *this;
618 ~Variant()
620 Impl::destroy(*this);
623 /** Check which variant type is currently contained. */
624 template<typename T>
625 bool is() const {
626 static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
627 "provided a type not uniquely found in this Variant's type list");
628 return Impl::template tag<T>() == tag;
631 template<size_t N>
632 bool is() const
634 static_assert(N < sizeof...(Ts),
635 "provided an index outside of this Variant's type list");
636 return N == size_t(tag);
640 * Operator == overload that defers to the variant type's operator==
641 * implementation if the rhs is tagged as the same type as this one.
643 bool operator==(const Variant& aRhs) const {
644 return tag == aRhs.tag && Impl::equal(*this, aRhs);
648 * Operator != overload that defers to the negation of the variant type's
649 * operator== implementation if the rhs is tagged as the same type as this
650 * one.
652 bool operator!=(const Variant& aRhs) const {
653 return !(*this == aRhs);
656 // Accessors for working with the contained variant value.
658 /** Mutable reference. */
659 template<typename T>
660 T& as() {
661 static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
662 "provided a type not uniquely found in this Variant's type list");
663 MOZ_RELEASE_ASSERT(is<T>());
664 return *static_cast<T*>(ptr());
667 template<size_t N>
668 typename detail::Nth<N, Ts...>::Type& as()
670 static_assert(N < sizeof...(Ts),
671 "provided an index outside of this Variant's type list");
672 MOZ_RELEASE_ASSERT(is<N>());
673 return *static_cast<typename detail::Nth<N, Ts...>::Type*>(ptr());
676 /** Immutable const reference. */
677 template<typename T>
678 const T& as() const {
679 static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
680 "provided a type not found in this Variant's type list");
681 MOZ_RELEASE_ASSERT(is<T>());
682 return *static_cast<const T*>(ptr());
685 template<size_t N>
686 const typename detail::Nth<N, Ts...>::Type& as() const
688 static_assert(N < sizeof...(Ts),
689 "provided an index outside of this Variant's type list");
690 MOZ_RELEASE_ASSERT(is<N>());
691 return *static_cast<const typename detail::Nth<N, Ts...>::Type*>(ptr());
695 * Extract the contained variant value from this container into a temporary
696 * value. On completion, the value in the variant will be in a
697 * safely-destructible state, as determined by the behavior of T's move
698 * constructor when provided the variant's internal value.
700 template<typename T>
701 T extract() {
702 static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
703 "provided a type not uniquely found in this Variant's type list");
704 MOZ_ASSERT(is<T>());
705 return T(Move(as<T>()));
708 template<size_t N>
709 typename detail::Nth<N, Ts...>::Type extract()
711 static_assert(N < sizeof...(Ts),
712 "provided an index outside of this Variant's type list");
713 MOZ_RELEASE_ASSERT(is<N>());
714 return typename detail::Nth<N, Ts...>::Type(Move(as<N>()));
717 // Exhaustive matching of all variant types on the contained value.
719 /** Match on an immutable const reference. */
720 template<typename Matcher>
721 auto
722 match(Matcher&& aMatcher) const
723 -> decltype(Impl::match(aMatcher, *this))
725 return Impl::match(aMatcher, *this);
728 /** Match on a mutable non-const reference. */
729 template<typename Matcher>
730 auto
731 match(Matcher&& aMatcher)
732 -> decltype(Impl::match(aMatcher, *this))
734 return Impl::match(aMatcher, *this);
739 * AsVariant() is used to construct a Variant<T,...> value containing the
740 * provided T value using type inference. It can be used to construct Variant
741 * values in expressions or return them from functions without specifying the
742 * entire Variant type.
744 * Because AsVariant() must copy or move the value into a temporary and this
745 * cannot necessarily be elided by the compiler, it's mostly appropriate only
746 * for use with primitive or very small types.
748 * AsVariant() returns a AsVariantTemporary value which is implicitly
749 * convertible to any Variant that can hold a value of type T.
751 template<typename T>
752 detail::AsVariantTemporary<T>
753 AsVariant(T&& aValue)
755 return detail::AsVariantTemporary<T>(Forward<T>(aValue));
758 } // namespace mozilla
760 #endif /* mozilla_Variant_h */