Bug 1246838 - Handle const qualifiers and references better in Variant. r=waldo
authorSeth Fowler <mark.seth.fowler@gmail.com>
Thu, 25 Feb 2016 14:34:12 -0800
changeset 285646 a48d1a9ea9063396b6600357a2b5014274f2d777
parent 285645 7381731bbb411698aa74352841f79a7fb13020c3
child 285647 8901dd8c722185016e3ccc2c4056dedfbf6a033a
push id72451
push usermfowler@mozilla.com
push dateThu, 25 Feb 2016 22:54:44 +0000
treeherdermozilla-inbound@8901dd8c7221 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswaldo
bugs1246838
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1246838 - Handle const qualifiers and references better in Variant. r=waldo
mfbt/Variant.h
--- a/mfbt/Variant.h
+++ b/mfbt/Variant.h
@@ -56,16 +56,64 @@ template<typename Needle, typename... Ha
 struct IsVariant<Needle, Needle, Haystack...>
 {
   static const bool value = true;
 };
 
 template<typename Needle, typename T, typename... Haystack>
 struct IsVariant<Needle, T, Haystack...> : public IsVariant<Needle, Haystack...> { };
 
+/// SelectVariantTypeHelper is used in the implementation of SelectVariantType.
+template<typename T, typename... Variants>
+struct SelectVariantTypeHelper;
+
+template<typename T>
+struct SelectVariantTypeHelper<T>
+{ };
+
+template<typename T, typename... Variants>
+struct SelectVariantTypeHelper<T, T, Variants...>
+{
+  typedef T Type;
+};
+
+template<typename T, typename... Variants>
+struct SelectVariantTypeHelper<T, const T, Variants...>
+{
+  typedef const T Type;
+};
+
+template<typename T, typename... Variants>
+struct SelectVariantTypeHelper<T, const T&, Variants...>
+{
+  typedef const T& Type;
+};
+
+template<typename T, typename... Variants>
+struct SelectVariantTypeHelper<T, T&&, Variants...>
+{
+  typedef T&& Type;
+};
+
+template<typename T, typename Head, typename... Variants>
+struct SelectVariantTypeHelper<T, Head, Variants...>
+  : public SelectVariantTypeHelper<T, Variants...>
+{ };
+
+/**
+ * SelectVariantType takes a type T and a list of variant types Variants and
+ * yields a type Type, selected from Variants, that can store a value of type T
+ * or a reference to type T. If no such type was found, Type is not defined.
+ */
+template <typename T, typename... Variants>
+struct SelectVariantType
+  : public SelectVariantTypeHelper<typename RemoveConst<typename RemoveReference<T>::Type>::Type,
+                                   Variants...>
+{ };
+
 // TagHelper gets the given sentinel tag value for the given type T. This has to
 // be split out from VariantImplementation because you can't nest a partial template
 // specialization within a template class.
 
 template<size_t N, typename T, typename U, typename Next, bool isMatch>
 struct TagHelper;
 
 // In the case where T != U, we continue recursion.
@@ -331,18 +379,17 @@ class Variant
 
 public:
   /** Perfect forwarding construction for some variant type T. */
   template<typename RefT,
            // RefT captures both const& as well as && (as intended, to support
            // perfect forwarding), so we have to remove those qualifiers here
            // when ensuring that T is a variant of this type, and getting T's
            // tag, etc.
-           typename T = typename RemoveReference<typename RemoveConst<RefT>::Type>::Type,
-           typename = typename EnableIf<detail::IsVariant<T, Ts...>::value, void>::Type>
+           typename T = typename detail::SelectVariantType<RefT, Ts...>::Type>
   explicit Variant(RefT&& aT)
     : tag(Impl::template tag<T>())
   {
     new (ptr()) T(Forward<T>(aT));
   }
 
   /** Copy construction. */
   Variant(const Variant& aRhs)