[libc++] Add __is_callable type trait and begin granularizing type_traits
authorNikolas Klauser <nikolasklauser@berlin.de>
Thu, 7 Apr 2022 11:40:53 +0000 (13:40 +0200)
committerNikolas Klauser <nikolasklauser@berlin.de>
Fri, 8 Apr 2022 10:23:52 +0000 (12:23 +0200)
`__is_callable` is required to ensure that the classic algorithms are only called with functions or functors. I also begin to granularize `<type_traits>`.

Reviewed By: ldionne, #libc

Spies: libcxx-commits, mgorny

Differential Revision: https://reviews.llvm.org/D123114

libcxx/include/CMakeLists.txt
libcxx/include/__type_traits/integral_constant.h [new file with mode: 0644]
libcxx/include/__type_traits/is_callable.h [new file with mode: 0644]
libcxx/include/module.modulemap
libcxx/include/type_traits
libcxx/test/libcxx/private_headers.verify.cpp
libcxx/test/libcxx/type_traits/is_callable.compile.pass.cpp [new file with mode: 0644]

index be544cf..5069d06 100644 (file)
@@ -411,6 +411,8 @@ set(files
   __threading_support
   __tree
   __tuple
+  __type_traits/integral_constant.h
+  __type_traits/is_callable.h
   __undef_macros
   __utility/as_const.h
   __utility/auto_cast.h
diff --git a/libcxx/include/__type_traits/integral_constant.h b/libcxx/include/__type_traits/integral_constant.h
new file mode 100644 (file)
index 0000000..2449d1a
--- /dev/null
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___TYPE_TRAITS_INTEGRAL_CONSTANT_H
+#define _LIBCPP___TYPE_TRAITS_INTEGRAL_CONSTANT_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Tp, _Tp __v>
+struct _LIBCPP_TEMPLATE_VIS integral_constant
+{
+  static _LIBCPP_CONSTEXPR const _Tp      value = __v;
+  typedef _Tp               value_type;
+  typedef integral_constant type;
+  _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_CONSTEXPR operator value_type() const _NOEXCEPT {return value;}
+#if _LIBCPP_STD_VER > 11
+  _LIBCPP_INLINE_VISIBILITY
+  constexpr value_type operator ()() const _NOEXCEPT {return value;}
+#endif
+};
+
+template <class _Tp, _Tp __v>
+_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value;
+
+typedef integral_constant<bool, true>  true_type;
+typedef integral_constant<bool, false> false_type;
+
+template <bool _Val>
+using _BoolConstant _LIBCPP_NODEBUG = integral_constant<bool, _Val>;
+
+#if _LIBCPP_STD_VER > 14
+template <bool __b>
+using bool_constant = integral_constant<bool, __b>;
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_INTEGRAL_CONSTANT_H
diff --git a/libcxx/include/__type_traits/is_callable.h b/libcxx/include/__type_traits/is_callable.h
new file mode 100644 (file)
index 0000000..73f894d
--- /dev/null
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___TYPE_TRAITS_IS_CALLABLE_H
+#define _LIBCPP___TYPE_TRAITS_IS_CALLABLE_H
+
+#include <__config>
+#include <__type_traits/integral_constant.h>
+#include <__utility/declval.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template<class _Func, class... _Args, class = decltype(std::declval<_Func>()(std::declval<_Args>()...))>
+true_type __is_callable_helper(int);
+template<class...>
+false_type __is_callable_helper(...);
+
+template<class _Func, class... _Args>
+struct __is_callable : decltype(__is_callable_helper<_Func, _Args...>(0)) {};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_IS_CALLABLE_H
index cf74a07..0f07fd1 100644 (file)
@@ -956,6 +956,9 @@ module std [system] {
     header "type_traits"
     export functional.__functional.unwrap_ref
     export *
+
+    module integral_constant { private header "__type_traits/integral_constant.h" }
+    module is_callable       { private header "__type_traits/is_callable.h" }
   }
   module typeindex {
     header "typeindex"
index 2ea883f..4f00e90 100644 (file)
@@ -419,6 +419,9 @@ namespace std
 
 #include <__assert> // all public C++ headers provide the assertion handler
 #include <__config>
+#include <__type_traits/integral_constant.h>
+#include <__type_traits/is_callable.h>
+#include <__utility/declval.h>
 #include <cstddef>
 #include <version>
 
@@ -432,28 +435,6 @@ template <class _T1, class _T2> struct _LIBCPP_TEMPLATE_VIS pair;
 template <class _Tp> class _LIBCPP_TEMPLATE_VIS reference_wrapper;
 template <class _Tp> struct _LIBCPP_TEMPLATE_VIS hash;
 
-template <class _Tp, _Tp __v>
-struct _LIBCPP_TEMPLATE_VIS integral_constant
-{
-  static _LIBCPP_CONSTEXPR const _Tp      value = __v;
-  typedef _Tp               value_type;
-  typedef integral_constant type;
-  _LIBCPP_INLINE_VISIBILITY
-  _LIBCPP_CONSTEXPR operator value_type() const _NOEXCEPT {return value;}
-#if _LIBCPP_STD_VER > 11
-  _LIBCPP_INLINE_VISIBILITY
-  constexpr value_type operator ()() const _NOEXCEPT {return value;}
-#endif
-};
-
-template <class _Tp, _Tp __v>
-_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value;
-
-#if _LIBCPP_STD_VER > 14
-template <bool __b>
-using bool_constant = integral_constant<bool, __b>;
-#endif
-
 template <bool, class _Tp = void> struct _LIBCPP_TEMPLATE_VIS enable_if {};
 template <class _Tp> struct _LIBCPP_TEMPLATE_VIS enable_if<true, _Tp> {typedef _Tp type;};
 
@@ -463,12 +444,6 @@ template <bool _Bp, class _Tp = void> using __enable_if_t _LIBCPP_NODEBUG = type
 template <bool _Bp, class _Tp = void> using enable_if_t = typename enable_if<_Bp, _Tp>::type;
 #endif
 
-typedef integral_constant<bool, true>  true_type;
-typedef integral_constant<bool, false> false_type;
-
-template <bool _Val>
-using _BoolConstant _LIBCPP_NODEBUG = integral_constant<bool, _Val>;
-
 template <bool> struct _MetaBase;
 template <>
 struct _MetaBase<true> {
@@ -1258,17 +1233,6 @@ template <class _Tp> struct _LIBCPP_TEMPLATE_VIS add_rvalue_reference
 template <class _Tp> using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type;
 #endif
 
-// Suppress deprecation notice for volatile-qualified return type resulting
-// from volatile-qualified types _Tp.
-_LIBCPP_SUPPRESS_DEPRECATED_PUSH
-template <class _Tp> _Tp&& __declval(int);
-template <class _Tp> _Tp   __declval(long);
-_LIBCPP_SUPPRESS_DEPRECATED_POP
-
-template <class _Tp>
-decltype(__declval<_Tp>(0))
-declval() _NOEXCEPT;
-
 template <class _Tp>
 struct __unconstref {
     typedef _LIBCPP_NODEBUG typename remove_const<typename remove_reference<_Tp>::type>::type type;
index f7117dd..f1173ff 100644 (file)
@@ -421,6 +421,8 @@ END-SCRIPT
 #include <__thread/poll_with_backoff.h> // expected-error@*:* {{use of private header from outside its module: '__thread/poll_with_backoff.h'}}
 #include <__thread/timed_backoff_policy.h> // expected-error@*:* {{use of private header from outside its module: '__thread/timed_backoff_policy.h'}}
 #include <__tuple> // expected-error@*:* {{use of private header from outside its module: '__tuple'}}
+#include <__type_traits/integral_constant.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/integral_constant.h'}}
+#include <__type_traits/is_callable.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/is_callable.h'}}
 #include <__utility/as_const.h> // expected-error@*:* {{use of private header from outside its module: '__utility/as_const.h'}}
 #include <__utility/auto_cast.h> // expected-error@*:* {{use of private header from outside its module: '__utility/auto_cast.h'}}
 #include <__utility/cmp.h> // expected-error@*:* {{use of private header from outside its module: '__utility/cmp.h'}}
diff --git a/libcxx/test/libcxx/type_traits/is_callable.compile.pass.cpp b/libcxx/test/libcxx/type_traits/is_callable.compile.pass.cpp
new file mode 100644 (file)
index 0000000..f7f76bb
--- /dev/null
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <type_traits>
+
+struct Functor {
+  void operator()();
+};
+
+int func();
+
+struct NotFunctor {
+  bool compare();
+};
+
+struct ArgumentFunctor {
+  bool operator()(int, int);
+};
+
+static_assert(std::__is_callable<Functor>::value, "");
+static_assert(std::__is_callable<decltype(func)>::value, "");
+static_assert(!std::__is_callable<NotFunctor>::value, "");
+static_assert(!std::__is_callable<NotFunctor,
+                                  decltype(&NotFunctor::compare)>::value, "");
+static_assert(std::__is_callable<ArgumentFunctor, int, int>::value, "");
+static_assert(!std::__is_callable<ArgumentFunctor, int>::value, "");