[libc++] Add __is_callable type trait and begin granularizing type_traits

`__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
This commit is contained in:
Nikolas Klauser 2022-04-07 13:40:53 +02:00
parent 628fcfd520
commit 08920cc043
7 changed files with 123 additions and 39 deletions

View 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

View File

@ -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

View File

@ -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

View 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"

View 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;

View 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'}}

View File

@ -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, "");