[libcxx-commits] [PATCH] D63574: Implement P0340R3: Make `underlying_type` SFINAE-friendly

Marshall Clow via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jun 19 14:27:39 PDT 2019


mclow.lists created this revision.
mclow.lists added reviewers: rsmith, EricWF, ldionne, zoecarver.
Herald added subscribers: dexonsmith, christof.

https://wg21.link/P0340R3

There are two possible approaches here:

- A library-only solution (this patch)
- Some compiler work (updating the `__underlying_type` intrinsic)

After working on this for a bit, I think this is the better approach.


Repository:
  rCXX libc++

https://reviews.llvm.org/D63574

Files:
  libcxx/include/type_traits
  libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp
  libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp


Index: libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
===================================================================
--- libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
+++ libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp
@@ -15,6 +15,18 @@
 
 #include "test_macros.h"
 
+#if TEST_STD_VER > 17
+template <class, class = std::void_t<>>
+struct has_type_member : std::false_type {};
+
+template <class T>
+struct has_type_member<T,
+           std::void_t<typename std::underlying_type<T>::type>> : std::true_type {};
+
+struct S {};
+#endif
+
+
 enum E { V = INT_MIN };
 
 #if !defined(_WIN32) || defined(__MINGW32__)
@@ -50,5 +62,18 @@
 #endif // TEST_STD_VER > 11
 #endif // TEST_STD_VER >= 11
 
+#if TEST_STD_VER > 17
+	static_assert( has_type_member<E>::value, "");
+	static_assert( has_type_member<F>::value, "");
+	static_assert( has_type_member<G>::value, "");
+
+	static_assert(!has_type_member<void>::value, "");
+	static_assert(!has_type_member<int>::value, "");
+	static_assert(!has_type_member<int[]>::value, "");
+	static_assert(!has_type_member<S>::value, "");
+	static_assert(!has_type_member<decltype(main)>::value, "");
+	static_assert(!has_type_member<int&>::value, "");
+#endif
+
   return 0;
 }
Index: libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp
===================================================================
--- /dev/null
+++ libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++98, c++03, c++11, C++14, c++17
+// type_traits
+
+// underlying_type
+// Mandates: enum must not be an incomplete enumeration type.
+
+#include <type_traits>
+#include <climits>
+
+#include "test_macros.h"
+
+enum E1 { zero, one, two = sizeof(std::underlying_type<E1>::type) };
+
+int main(int, char**)
+{
+  return 0;
+}
Index: libcxx/include/type_traits
===================================================================
--- libcxx/include/type_traits
+++ libcxx/include/type_traits
@@ -4726,8 +4726,14 @@
 
 #ifdef _LIBCPP_UNDERLYING_TYPE
 
+template <class _Tp, bool = is_enum<_Tp>::value> struct underlying_type;
+
+
 template <class _Tp>
-struct underlying_type
+struct underlying_type<_Tp, false> {};
+
+template <class _Tp>
+struct underlying_type<_Tp, true>
 {
     typedef _LIBCPP_UNDERLYING_TYPE(_Tp) type;
 };


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D63574.205672.patch
Type: text/x-patch
Size: 2824 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20190619/bf38feb7/attachment.bin>


More information about the libcxx-commits mailing list