Fix folly::to<> under MSVC
authorChristopher Dykes <cdykes@fb.com>
Sun, 21 Aug 2016 17:02:29 +0000 (10:02 -0700)
committerFacebook Github Bot 0 <facebook-github-bot-0-bot@fb.com>
Sun, 21 Aug 2016 17:08:30 +0000 (10:08 -0700)
Summary: MSVC didn't like the conversion to using `Expected`, and, after `Expected` was fixed to work under MSVC, conv still needs more changes. Specifically MSVC doesn't understand the single-instantiation form of getting the last element, so we have to switch to a tuple-backed version instead, which requires more template instantions, but produces the same performance at runtime.

Reviewed By: ericniebler

Differential Revision: D3744063

fbshipit-source-id: affcab1574c721d8b9529784d7ca2a46233d9935

folly/Conv.h

index 09f762bc7d9f7638dfc40960ed65869420adebdd..468d33cb08a74d467b9ed9366499f30aa87dc88e 100644 (file)
@@ -187,6 +187,33 @@ to(const Src& value) {
 
 namespace detail {
 
+#ifdef _MSC_VER
+// MSVC can't quite figure out the LastElementImpl::call() stuff
+// in the base implementation, so we have to use tuples instead,
+// which result in significantly more templates being compiled,
+// though the runtime performance is the same.
+
+template <typename... Ts>
+auto getLastElement(Ts&&... ts) -> decltype(
+    std::get<sizeof...(Ts)-1>(std::forward_as_tuple(std::forward<Ts>(ts)...))) {
+  return std::get<sizeof...(Ts)-1>(
+      std::forward_as_tuple(std::forward<Ts>(ts)...));
+}
+
+inline void getLastElement() {}
+
+template <size_t size, typename... Ts>
+struct LastElementType : std::tuple_element<size - 1, std::tuple<Ts...>> {};
+
+template <>
+struct LastElementType<0> {
+  using type = void;
+};
+
+template <class... Ts>
+struct LastElement
+    : std::decay<typename LastElementType<sizeof...(Ts), Ts...>::type> {};
+#else
 template <typename... Ts>
 struct LastElementImpl {
   static void call(Ignored<Ts>...) {}
@@ -210,6 +237,7 @@ template <class... Ts>
 struct LastElement : std::decay<decltype(
                          LastElementImpl<Ts...>::call(std::declval<Ts>()...))> {
 };
+#endif
 
 } // namespace detail