Bug 1531915 [wpt PR 15578] - Fix flakiness of external/wpt/css/css-position/z-index...
[gecko.git] / mfbt / Variant.h
blob581ca2d686edf2fca855ed2d49b3e30b9fa1a12a
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>
23 struct ParamTraits;
24 } // namespace IPC
26 namespace mozilla {
28 template <typename... Ts>
29 class Variant;
31 namespace detail {
33 // Nth<N, types...>::Type is the Nth type (0-based) in the list of types Ts.
34 template <size_t N, typename... Ts>
35 struct Nth;
37 template <typename T, typename... Ts>
38 struct Nth<0, T, Ts...> {
39 using Type = T;
42 template <size_t N, typename T, typename... Ts>
43 struct Nth<N, T, Ts...> {
44 using Type = typename Nth<N - 1, Ts...>::Type;
47 /// SelectVariantTypeHelper is used in the implementation of SelectVariantType.
48 template <typename T, typename... Variants>
49 struct SelectVariantTypeHelper;
51 template <typename T>
52 struct SelectVariantTypeHelper<T> {
53 static constexpr size_t count = 0;
56 template <typename T, typename... Variants>
57 struct SelectVariantTypeHelper<T, T, Variants...> {
58 typedef T Type;
59 static constexpr size_t count =
60 1 + SelectVariantTypeHelper<T, Variants...>::count;
63 template <typename T, typename... Variants>
64 struct SelectVariantTypeHelper<T, const T, Variants...> {
65 typedef const T Type;
66 static constexpr size_t count =
67 1 + SelectVariantTypeHelper<T, Variants...>::count;
70 template <typename T, typename... Variants>
71 struct SelectVariantTypeHelper<T, const T&, Variants...> {
72 typedef const T& Type;
73 static constexpr size_t count =
74 1 + SelectVariantTypeHelper<T, Variants...>::count;
77 template <typename T, typename... Variants>
78 struct SelectVariantTypeHelper<T, T&&, Variants...> {
79 typedef T&& Type;
80 static constexpr size_t count =
81 1 + SelectVariantTypeHelper<T, Variants...>::count;
84 template <typename T, typename Head, typename... Variants>
85 struct SelectVariantTypeHelper<T, Head, Variants...>
86 : public SelectVariantTypeHelper<T, Variants...> {};
88 /**
89 * SelectVariantType takes a type T and a list of variant types Variants and
90 * yields a type Type, selected from Variants, that can store a value of type T
91 * or a reference to type T. If no such type was found, Type is not defined.
92 * SelectVariantType also has a `count` member that contains the total number of
93 * selectable types (which will be used to check that a requested type is not
94 * ambiguously present twice.)
96 template <typename T, typename... Variants>
97 struct SelectVariantType
98 : public SelectVariantTypeHelper<
99 typename RemoveConst<typename RemoveReference<T>::Type>::Type,
100 Variants...> {};
102 // Compute a fast, compact type that can be used to hold integral values that
103 // distinctly map to every type in Ts.
104 template <typename... Ts>
105 struct VariantTag {
106 private:
107 static const size_t TypeCount = sizeof...(Ts);
109 public:
110 using Type = typename Conditional < TypeCount < 3, bool,
111 typename Conditional<TypeCount<(1 << 8), uint_fast8_t,
112 size_t // stop caring past a certain
113 // point :-)
114 >::Type>::Type;
117 // TagHelper gets the given sentinel tag value for the given type T. This has to
118 // be split out from VariantImplementation because you can't nest a partial
119 // template specialization within a template class.
121 template <typename Tag, size_t N, typename T, typename U, typename Next,
122 bool isMatch>
123 struct TagHelper;
125 // In the case where T != U, we continue recursion.
126 template <typename Tag, size_t N, typename T, typename U, typename Next>
127 struct TagHelper<Tag, N, T, U, Next, false> {
128 static Tag tag() { return Next::template tag<U>(); }
131 // In the case where T == U, return the tag number.
132 template <typename Tag, size_t N, typename T, typename U, typename Next>
133 struct TagHelper<Tag, N, T, U, Next, true> {
134 static Tag tag() { return Tag(N); }
137 // The VariantImplementation template provides the guts of mozilla::Variant. We
138 // create a VariantImplementation for each T in Ts... which handles
139 // construction, destruction, etc for when the Variant's type is T. If the
140 // Variant's type isn't T, it punts the request on to the next
141 // VariantImplementation.
143 template <typename Tag, size_t N, typename... Ts>
144 struct VariantImplementation;
146 // The singly typed Variant / recursion base case.
147 template <typename Tag, size_t N, typename T>
148 struct VariantImplementation<Tag, N, T> {
149 template <typename U>
150 static Tag tag() {
151 static_assert(mozilla::IsSame<T, U>::value,
152 "mozilla::Variant: tag: bad type!");
153 return Tag(N);
156 template <typename Variant>
157 static void copyConstruct(void* aLhs, const Variant& aRhs) {
158 ::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
161 template <typename Variant>
162 static void moveConstruct(void* aLhs, Variant&& aRhs) {
163 ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
166 template <typename Variant>
167 static void destroy(Variant& aV) {
168 aV.template as<N>().~T();
171 template <typename Variant>
172 static bool equal(const Variant& aLhs, const Variant& aRhs) {
173 return aLhs.template as<N>() == aRhs.template as<N>();
176 template <typename Matcher, typename ConcreteVariant>
177 static auto match(Matcher&& aMatcher, ConcreteVariant& aV)
178 -> decltype(aMatcher.match(aV.template as<N>())) {
179 return aMatcher.match(aV.template as<N>());
183 // VariantImplementation for some variant type T.
184 template <typename Tag, size_t N, typename T, typename... Ts>
185 struct VariantImplementation<Tag, N, T, Ts...> {
186 // The next recursive VariantImplementation.
187 using Next = VariantImplementation<Tag, N + 1, Ts...>;
189 template <typename U>
190 static Tag tag() {
191 return TagHelper<Tag, N, T, U, Next, IsSame<T, U>::value>::tag();
194 template <typename Variant>
195 static void copyConstruct(void* aLhs, const Variant& aRhs) {
196 if (aRhs.template is<N>()) {
197 ::new (KnownNotNull, aLhs) T(aRhs.template as<N>());
198 } else {
199 Next::copyConstruct(aLhs, aRhs);
203 template <typename Variant>
204 static void moveConstruct(void* aLhs, Variant&& aRhs) {
205 if (aRhs.template is<N>()) {
206 ::new (KnownNotNull, aLhs) T(aRhs.template extract<N>());
207 } else {
208 Next::moveConstruct(aLhs, std::move(aRhs));
212 template <typename Variant>
213 static void destroy(Variant& aV) {
214 if (aV.template is<N>()) {
215 aV.template as<N>().~T();
216 } else {
217 Next::destroy(aV);
221 template <typename Variant>
222 static bool equal(const Variant& aLhs, const Variant& aRhs) {
223 if (aLhs.template is<N>()) {
224 MOZ_ASSERT(aRhs.template is<N>());
225 return aLhs.template as<N>() == aRhs.template as<N>();
226 } else {
227 return Next::equal(aLhs, aRhs);
231 template <typename Matcher, typename ConcreteVariant>
232 static auto match(Matcher&& aMatcher, ConcreteVariant& aV)
233 -> decltype(aMatcher.match(aV.template as<N>())) {
234 if (aV.template is<N>()) {
235 return aMatcher.match(aV.template as<N>());
236 } else {
237 // If you're seeing compilation errors here like "no matching
238 // function for call to 'match'" then that means that the
239 // Matcher doesn't exhaust all variant types. There must exist a
240 // Matcher::match(T&) for every variant type T.
242 // If you're seeing compilation errors here like "cannot
243 // initialize return object of type <...> with an rvalue of type
244 // <...>" then that means that the Matcher::match(T&) overloads
245 // are returning different types. They must all return the same
246 // Matcher::ReturnType type.
247 return Next::match(aMatcher, aV);
253 * AsVariantTemporary stores a value of type T to allow construction of a
254 * Variant value via type inference. Because T is copied and there's no
255 * guarantee that the copy can be elided, AsVariantTemporary is best used with
256 * primitive or very small types.
258 template <typename T>
259 struct AsVariantTemporary {
260 explicit AsVariantTemporary(const T& aValue) : mValue(aValue) {}
262 template <typename U>
263 explicit AsVariantTemporary(U&& aValue) : mValue(std::forward<U>(aValue)) {}
265 AsVariantTemporary(const AsVariantTemporary& aOther)
266 : mValue(aOther.mValue) {}
268 AsVariantTemporary(AsVariantTemporary&& aOther)
269 : mValue(std::move(aOther.mValue)) {}
271 AsVariantTemporary() = delete;
272 void operator=(const AsVariantTemporary&) = delete;
273 void operator=(AsVariantTemporary&&) = delete;
275 typename RemoveConst<typename RemoveReference<T>::Type>::Type mValue;
278 } // namespace detail
280 // Used to unambiguously specify one of the Variant's type.
281 template <typename T>
282 struct VariantType {
283 using Type = T;
286 // Used to specify one of the Variant's type by index.
287 template <size_t N>
288 struct VariantIndex {
289 static constexpr size_t index = N;
293 * # mozilla::Variant
295 * A variant / tagged union / heterogenous disjoint union / sum-type template
296 * class. Similar in concept to (but not derived from) `boost::variant`.
298 * Sometimes, you may wish to use a C union with non-POD types. However, this is
299 * forbidden in C++ because it is not clear which type in the union should have
300 * its constructor and destructor run on creation and deletion
301 * respectively. This is the problem that `mozilla::Variant` solves.
303 * ## Usage
305 * A `mozilla::Variant` instance is constructed (via move or copy) from one of
306 * its variant types (ignoring const and references). It does *not* support
307 * construction from subclasses of variant types or types that coerce to one of
308 * the variant types.
310 * Variant<char, uint32_t> v1('a');
311 * Variant<UniquePtr<A>, B, C> v2(MakeUnique<A>());
312 * Variant<bool, char> v3(VariantType<char>, 0); // disambiguation needed
313 * Variant<int, int> v4(VariantIndex<1>, 0); // 2nd int
315 * Because specifying the full type of a Variant value is often verbose,
316 * there are two easier ways to construct values:
318 * A. AsVariant() can be used to construct a Variant value using type inference
319 * in contexts such as expressions or when returning values from functions.
320 * Because AsVariant() must copy or move the value into a temporary and this
321 * cannot necessarily be elided by the compiler, it's mostly appropriate only
322 * for use with primitive or very small types.
324 * Variant<char, uint32_t> Foo() { return AsVariant('x'); }
325 * // ...
326 * Variant<char, uint32_t> v1 = Foo(); // v1 holds char('x').
328 * B. Brace-construction with VariantType or VariantIndex; this also allows
329 * in-place construction with any number of arguments.
331 * struct AB { AB(int, int){...} };
332 * static Variant<AB, bool> foo()
334 * return {VariantIndex<0>{}, 1, 2};
336 * // ...
337 * Variant<AB, bool> v0 = Foo(); // v0 holds AB(1,2).
339 * All access to the contained value goes through type-safe accessors.
340 * Either the stored type, or the type index may be provided.
342 * void
343 * Foo(Variant<A, B, C> v)
345 * if (v.is<A>()) {
346 * A& ref = v.as<A>();
347 * ...
348 * } else (v.is<1>()) { // Instead of v.is<B>.
349 * ...
350 * } else {
351 * ...
355 * In some situation, a Variant may be constructed from templated types, in
356 * which case it is possible that the same type could be given multiple times by
357 * an external developer. Or seemingly-different types could be aliases.
358 * In this case, repeated types can only be accessed through their index, to
359 * prevent ambiguous access by type.
361 * // Bad!
362 * template <typename T>
363 * struct ResultOrError
365 * Variant<T, int> m;
366 * ResultOrError() : m(int(0)) {} // Error '0' by default
367 * ResultOrError(const T& r) : m(r) {}
368 * bool IsResult() const { return m.is<T>(); }
369 * bool IsError() const { return m.is<int>(); }
370 * };
371 * // Now instantiante with the result being an int too:
372 * ResultOrError<int> myResult(123); // Fail!
373 * // In Variant<int, int>, which 'int' are we refering to, from inside
374 * // ResultOrError functions?
376 * // Good!
377 * template <typename T>
378 * struct ResultOrError
380 * Variant<T, int> m;
381 * ResultOrError() : m(VariantIndex<1>{}, 0) {} // Error '0' by default
382 * ResultOrError(const T& r) : m(VariantIndex<0>{}, r) {}
383 * bool IsResult() const { return m.is<0>(); } // 0 -> T
384 * bool IsError() const { return m.is<1>(); } // 1 -> int
385 * };
386 * // Now instantiante with the result being an int too:
387 * ResultOrError<int> myResult(123); // It now works!
389 * Attempting to use the contained value as type `T1` when the `Variant`
390 * instance contains a value of type `T2` causes an assertion failure.
392 * A a;
393 * Variant<A, B, C> v(a);
394 * v.as<B>(); // <--- Assertion failure!
396 * Trying to use a `Variant<Ts...>` instance as some type `U` that is not a
397 * member of the set of `Ts...` is a compiler error.
399 * A a;
400 * Variant<A, B, C> v(a);
401 * v.as<SomeRandomType>(); // <--- Compiler error!
403 * Additionally, you can turn a `Variant` that `is<T>` into a `T` by moving it
404 * out of the containing `Variant` instance with the `extract<T>` method:
406 * Variant<UniquePtr<A>, B, C> v(MakeUnique<A>());
407 * auto ptr = v.extract<UniquePtr<A>>();
409 * Finally, you can exhaustively match on the contained variant and branch into
410 * different code paths depending on which type is contained. This is preferred
411 * to manually checking every variant type T with is<T>() because it provides
412 * compile-time checking that you handled every type, rather than runtime
413 * assertion failures.
415 * // Bad!
416 * char* foo(Variant<A, B, C, D>& v) {
417 * if (v.is<A>()) {
418 * return ...;
419 * } else if (v.is<B>()) {
420 * return ...;
421 * } else {
422 * return doSomething(v.as<C>()); // Forgot about case D!
426 * // Good!
427 * struct FooMatcher
429 * // The return type of all matchers must be identical.
430 * char* match(A& a) { ... }
431 * char* match(B& b) { ... }
432 * char* match(C& c) { ... }
433 * char* match(D& d) { ... } // Compile-time error to forget D!
435 * char* foo(Variant<A, B, C, D>& v) {
436 * return v.match(FooMatcher());
439 * ## Examples
441 * A tree is either an empty leaf, or a node with a value and two children:
443 * struct Leaf { };
445 * template<typename T>
446 * struct Node
448 * T value;
449 * Tree<T>* left;
450 * Tree<T>* right;
451 * };
453 * template<typename T>
454 * using Tree = Variant<Leaf, Node<T>>;
456 * A copy-on-write string is either a non-owning reference to some existing
457 * string, or an owning reference to our copy:
459 * class CopyOnWriteString
461 * Variant<const char*, UniquePtr<char[]>> string;
463 * ...
464 * };
466 * Because Variant must be aligned suitable to hold any value stored within it,
467 * and because |alignas| requirements don't affect platform ABI with respect to
468 * how parameters are laid out in memory, Variant can't be used as the type of a
469 * function parameter. Pass Variant to functions by pointer or reference
470 * instead.
472 template <typename... Ts>
473 class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant {
474 friend struct IPC::ParamTraits<mozilla::Variant<Ts...>>;
476 using Tag = typename detail::VariantTag<Ts...>::Type;
477 using Impl = detail::VariantImplementation<Tag, 0, Ts...>;
479 static constexpr size_t RawDataAlignment = tl::Max<alignof(Ts)...>::value;
480 static constexpr size_t RawDataSize = tl::Max<sizeof(Ts)...>::value;
482 // Raw storage for the contained variant value.
483 alignas(RawDataAlignment) unsigned char rawData[RawDataSize];
485 // Each type is given a unique tag value that lets us keep track of the
486 // contained variant value's type.
487 Tag tag;
489 // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
490 // -Werror compile error) to reinterpret_cast<> |rawData| to |T*|, even
491 // through |void*|. Placing the latter cast in these separate functions
492 // breaks the chain such that affected GCC versions no longer warn/error.
493 void* ptr() { return rawData; }
495 const void* ptr() const { return rawData; }
497 public:
498 /** Perfect forwarding construction for some variant type T. */
499 template <typename RefT,
500 // RefT captures both const& as well as && (as intended, to support
501 // perfect forwarding), so we have to remove those qualifiers here
502 // when ensuring that T is a variant of this type, and getting T's
503 // tag, etc.
504 typename T = typename detail::SelectVariantType<RefT, Ts...>::Type>
505 explicit Variant(RefT&& aT) : tag(Impl::template tag<T>()) {
506 static_assert(
507 detail::SelectVariantType<RefT, Ts...>::count == 1,
508 "Variant can only be selected by type if that type is unique");
509 ::new (KnownNotNull, ptr()) T(std::forward<RefT>(aT));
513 * Perfect forwarding construction for some variant type T, by
514 * explicitly giving the type.
515 * This is necessary to construct from any number of arguments,
516 * or to convert from a type that is not in the Variant's type list.
518 template <typename T, typename... Args>
519 MOZ_IMPLICIT Variant(const VariantType<T>&, Args&&... aTs)
520 : tag(Impl::template tag<T>()) {
521 ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...);
525 * Perfect forwarding construction for some variant type T, by
526 * explicitly giving the type index.
527 * This is necessary to construct from any number of arguments,
528 * or to convert from a type that is not in the Variant's type list,
529 * or to construct a type that is present more than once in the Variant.
531 template <size_t N, typename... Args>
532 MOZ_IMPLICIT Variant(const VariantIndex<N>&, Args&&... aTs) : tag(N) {
533 using T = typename detail::Nth<N, Ts...>::Type;
534 ::new (KnownNotNull, ptr()) T(std::forward<Args>(aTs)...);
538 * Constructs this Variant from an AsVariantTemporary<T> such that T can be
539 * stored in one of the types allowable in this Variant. This is used in the
540 * implementation of AsVariant().
542 template <typename RefT>
543 MOZ_IMPLICIT Variant(detail::AsVariantTemporary<RefT>&& aValue)
544 : tag(Impl::template tag<
545 typename detail::SelectVariantType<RefT, Ts...>::Type>()) {
546 using T = typename detail::SelectVariantType<RefT, Ts...>::Type;
547 static_assert(
548 detail::SelectVariantType<RefT, Ts...>::count == 1,
549 "Variant can only be selected by type if that type is unique");
550 ::new (KnownNotNull, ptr()) T(std::move(aValue.mValue));
553 /** Copy construction. */
554 Variant(const Variant& aRhs) : tag(aRhs.tag) {
555 Impl::copyConstruct(ptr(), aRhs);
558 /** Move construction. */
559 Variant(Variant&& aRhs) : tag(aRhs.tag) {
560 Impl::moveConstruct(ptr(), std::move(aRhs));
563 /** Copy assignment. */
564 Variant& operator=(const Variant& aRhs) {
565 MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
566 this->~Variant();
567 ::new (KnownNotNull, this) Variant(aRhs);
568 return *this;
571 /** Move assignment. */
572 Variant& operator=(Variant&& aRhs) {
573 MOZ_ASSERT(&aRhs != this, "self-assign disallowed");
574 this->~Variant();
575 ::new (KnownNotNull, this) Variant(std::move(aRhs));
576 return *this;
579 /** Move assignment from AsVariant(). */
580 template <typename T>
581 Variant& operator=(detail::AsVariantTemporary<T>&& aValue) {
582 static_assert(
583 detail::SelectVariantType<T, Ts...>::count == 1,
584 "Variant can only be selected by type if that type is unique");
585 this->~Variant();
586 ::new (KnownNotNull, this) Variant(std::move(aValue));
587 return *this;
590 ~Variant() { Impl::destroy(*this); }
592 /** Check which variant type is currently contained. */
593 template <typename T>
594 bool is() const {
595 static_assert(
596 detail::SelectVariantType<T, Ts...>::count == 1,
597 "provided a type not uniquely found in this Variant's type list");
598 return Impl::template tag<T>() == tag;
601 template <size_t N>
602 bool is() const {
603 static_assert(N < sizeof...(Ts),
604 "provided an index outside of this Variant's type list");
605 return N == size_t(tag);
609 * Operator == overload that defers to the variant type's operator==
610 * implementation if the rhs is tagged as the same type as this one.
612 bool operator==(const Variant& aRhs) const {
613 return tag == aRhs.tag && Impl::equal(*this, aRhs);
617 * Operator != overload that defers to the negation of the variant type's
618 * operator== implementation if the rhs is tagged as the same type as this
619 * one.
621 bool operator!=(const Variant& aRhs) const { return !(*this == aRhs); }
623 // Accessors for working with the contained variant value.
625 /** Mutable reference. */
626 template <typename T>
627 T& as() {
628 static_assert(
629 detail::SelectVariantType<T, Ts...>::count == 1,
630 "provided a type not uniquely found in this Variant's type list");
631 MOZ_RELEASE_ASSERT(is<T>());
632 return *static_cast<T*>(ptr());
635 template <size_t N>
636 typename detail::Nth<N, Ts...>::Type& as() {
637 static_assert(N < sizeof...(Ts),
638 "provided an index outside of this Variant's type list");
639 MOZ_RELEASE_ASSERT(is<N>());
640 return *static_cast<typename detail::Nth<N, Ts...>::Type*>(ptr());
643 /** Immutable const reference. */
644 template <typename T>
645 const T& as() const {
646 static_assert(detail::SelectVariantType<T, Ts...>::count == 1,
647 "provided a type not found in this Variant's type list");
648 MOZ_RELEASE_ASSERT(is<T>());
649 return *static_cast<const T*>(ptr());
652 template <size_t N>
653 const typename detail::Nth<N, Ts...>::Type& as() const {
654 static_assert(N < sizeof...(Ts),
655 "provided an index outside of this Variant's type list");
656 MOZ_RELEASE_ASSERT(is<N>());
657 return *static_cast<const typename detail::Nth<N, Ts...>::Type*>(ptr());
661 * Extract the contained variant value from this container into a temporary
662 * value. On completion, the value in the variant will be in a
663 * safely-destructible state, as determined by the behavior of T's move
664 * constructor when provided the variant's internal value.
666 template <typename T>
667 T extract() {
668 static_assert(
669 detail::SelectVariantType<T, Ts...>::count == 1,
670 "provided a type not uniquely found in this Variant's type list");
671 MOZ_ASSERT(is<T>());
672 return T(std::move(as<T>()));
675 template <size_t N>
676 typename detail::Nth<N, Ts...>::Type extract() {
677 static_assert(N < sizeof...(Ts),
678 "provided an index outside of this Variant's type list");
679 MOZ_RELEASE_ASSERT(is<N>());
680 return typename detail::Nth<N, Ts...>::Type(std::move(as<N>()));
683 // Exhaustive matching of all variant types on the contained value.
685 /** Match on an immutable const reference. */
686 template <typename Matcher>
687 auto match(Matcher&& aMatcher) const
688 -> decltype(Impl::match(aMatcher, *this)) {
689 return Impl::match(aMatcher, *this);
692 /** Match on a mutable non-const reference. */
693 template <typename Matcher>
694 auto match(Matcher&& aMatcher) -> decltype(Impl::match(aMatcher, *this)) {
695 return Impl::match(aMatcher, *this);
700 * AsVariant() is used to construct a Variant<T,...> value containing the
701 * provided T value using type inference. It can be used to construct Variant
702 * values in expressions or return them from functions without specifying the
703 * entire Variant type.
705 * Because AsVariant() must copy or move the value into a temporary and this
706 * cannot necessarily be elided by the compiler, it's mostly appropriate only
707 * for use with primitive or very small types.
709 * AsVariant() returns a AsVariantTemporary value which is implicitly
710 * convertible to any Variant that can hold a value of type T.
712 template <typename T>
713 detail::AsVariantTemporary<T> AsVariant(T&& aValue) {
714 return detail::AsVariantTemporary<T>(std::forward<T>(aValue));
717 } // namespace mozilla
719 #endif /* mozilla_Variant_h */