- moved is_detected in type_traits.h (#2794)

- fixed callable_traits
- added tests

Co-authored-by: pf <pf@me>
This commit is contained in:
pfeatherstone 2023-05-09 03:39:15 +01:00 committed by GitHub
parent 191d280d64
commit 775ac0799f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 43 deletions

View File

@ -13,12 +13,6 @@ namespace dlib
namespace detail
{
const auto _ = [](auto&& arg) -> decltype(auto) { return std::forward<decltype(arg)>(arg); };
template<typename Void, template <class...> class Op, class... Args>
struct is_detected : std::false_type{};
template<template <class...> class Op, class... Args>
struct is_detected<dlib::void_t<Op<Args...>>, Op, Args...> : std::true_type {};
}
// ----------------------------------------------------------------------------------------
@ -111,16 +105,9 @@ namespace dlib
{
return overloaded(std::forward<Cases>(cases)...)(types_<T>{}..., detail::_);
}
// ----------------------------------------------------------------------------------------
template<template <class...> class Op, class... Args>
using is_detected = detail::is_detected<void, Op, Args...>;
/*!
ensures
- This is exactly the same as std::experimental::is_detected from library fundamentals v
!*/
// ----------------------------------------------------------------------------------------
}
#endif //DLIB_IF_CONSTEXPR_H

View File

@ -95,6 +95,8 @@ namespace
static_assert(std::is_same<dlib::callable_return<decltype(func_testargs)>,
void>::value, "make this correct");
static_assert(is_callable<decltype(func_testargs)>::value, "bad");
static_assert(std::is_same<dlib::callable_args<decltype(func_return_addition)>,
dlib::types_<int, int>
>::value, "make this correct");
@ -111,6 +113,8 @@ namespace
static_assert(std::is_same<dlib::callable_return<decltype(func_return_addition)>,
int>::value, "make this correct");
static_assert(is_callable<decltype(func_return_addition)>::value, "bad");
{
std::string str = run1_str4;
@ -160,6 +164,8 @@ namespace
static_assert(std::is_same<dlib::callable_return<decltype(f)>,
long>::value, "make this correct");
static_assert(is_callable<decltype(f)>::value, "bad");
}
{
@ -228,6 +234,8 @@ namespace
static_assert(std::is_same<dlib::callable_return<example_struct>,
float>::value, "make this correct");
static_assert(is_callable<example_struct>::value, "bad");
void test_member_functions_and_data()
{
example_struct obj1(10);
@ -482,6 +490,7 @@ namespace
{
template <
class Callable,
std::enable_if_t<is_callable<Callable>::value, bool> = true,
std::enable_if_t<callable_nargs<Callable>::value >= 1, bool> = true,
std::enable_if_t<std::is_floating_point<callable_arg<0, Callable>>::value, bool> = true
>
@ -499,6 +508,7 @@ namespace
template <
class Callable,
std::enable_if_t<is_callable<Callable>::value, bool> = true,
std::enable_if_t<callable_nargs<Callable>::value >= 1, bool> = true,
std::enable_if_t<std::is_integral<callable_arg<0, Callable>>::value, bool> = true
>
@ -516,6 +526,7 @@ namespace
template <
class Callable,
std::enable_if_t<is_callable<Callable>::value, bool> = true,
std::enable_if_t<callable_nargs<Callable>::value < 1, bool> = true
>
auto wrap (
@ -543,6 +554,8 @@ namespace
const auto f6 = wrap(f3, i);
DLIB_TEST(i == 3);
}
static_assert(!is_callable<int>::value, "bad");
}
class invoke_tester : public tester

View File

@ -210,6 +210,24 @@ namespace dlib
template<class T>
using is_complete_type = details::is_complete_type<T>;
// ----------------------------------------------------------------------------------------
namespace details
{
template<typename Void, template <class...> class Op, class... Args>
struct is_detected : std::false_type{};
template<template <class...> class Op, class... Args>
struct is_detected<dlib::void_t<Op<Args...>>, Op, Args...> : std::true_type {};
}
template<template <class...> class Op, class... Args>
using is_detected = details::is_detected<void, Op, Args...>;
/*!
ensures
- This is exactly the same as std::experimental::is_detected from library fundamentals v
!*/
// ----------------------------------------------------------------------------------------
template<typename... T>
@ -264,50 +282,71 @@ namespace dlib
// ----------------------------------------------------------------------------------------
namespace details
{
template<class AlwaysVoid, class F>
struct callable_traits
{
constexpr static bool is_callable = false;
};
template<class AlwaysVoid, class R, class... Args>
struct callable_traits<AlwaysVoid, R(Args...)>
{
using return_type = R;
using args = types_<Args...>;
constexpr static std::size_t nargs = sizeof...(Args);
constexpr static bool is_callable = true;
};
template<class AlwaysVoid, class R, class... Args>
struct callable_traits<AlwaysVoid, R(*)(Args...)>
: public callable_traits<AlwaysVoid, R(Args...)>{};
template<class AlwaysVoid, class C, class R, class... Args>
struct callable_traits<AlwaysVoid, R(C::*)(Args...)>
: public callable_traits<AlwaysVoid, R(Args...)>{};
template<class AlwaysVoid, class C, class R, class... Args>
struct callable_traits<AlwaysVoid, R(C::*)(Args...) const>
: public callable_traits<AlwaysVoid, R(Args...)>{};
template<class F>
struct callable_traits<void_t<decltype(&std::decay_t<F>::operator())>, F>
: public callable_traits<void, decltype(&std::decay_t<F>::operator())>{};
}
template<class F>
struct callable_traits;
struct callable_traits : details::callable_traits<void, F> {};
/*!
WHAT THIS OBJECT REPRESENTS
This is a type trait for callable types like function pointers, functors and lambdas.
It provides the following types:
This is a type trait for callable types.
If the template parameter F is function pointer, functor or lambda then
it provides the following types:
return_type : the return type of the callable object
args : a parameter pack packaged in a types_<> meta container containing
all the function argument types
It also provides the following static members:
nargs : the number of function arguments
is_callable : a boolean which determines whether F is callable. In this case, it is true
If the template parameter F is not function-like object, then it provides:
is_callable : false
For example, a function type F with signature R(T1, T2, T3) has the following traits:
callable_traits<F>::return_type == R
callable_traits<F>::args == types_<T1,T2,T3>
callable_traits<F>::nargs == 3
callable_traits<F>::is_callable == true
Another example:
callable_traits<int>::is_callable == false
callable_traits<int>::return_type == does not exist. Compile error
callable_traits<int>::args == does not exist. Compile error
callable_traits<int>::nargs == does not exist. Compile error
!*/
template<class R, class... Args>
struct callable_traits<R(Args...)>
{
using return_type = R;
using args = types_<Args...>;
constexpr static std::size_t nargs = sizeof...(Args);
};
template<class R, class... Args>
struct callable_traits<R(*)(Args...)> : public callable_traits<R(Args...)>{};
template<class C, class R, class... Args>
struct callable_traits<R(C::*)(Args...)> : public callable_traits<R(Args...)>{};
template<class C, class R, class... Args>
struct callable_traits<R(C::*)(Args...) const> : public callable_traits<R(Args...)>{};
template<class F>
struct callable_traits
{
using call_type = callable_traits<decltype(&std::decay_t<F>::operator())>;
using return_type = typename call_type::return_type;
using args = typename call_type::args;
constexpr static std::size_t nargs = call_type::nargs;
};
template<class Callable>
using callable_args = typename callable_traits<Callable>::args;
@ -320,6 +359,9 @@ namespace dlib
template<class Callable>
using callable_return = typename callable_traits<Callable>::return_type;
template<class F>
using is_callable = std::integral_constant<bool, callable_traits<F>::is_callable>;
// ----------------------------------------------------------------------------------------
}