- 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 namespace detail
{ {
const auto _ = [](auto&& arg) -> decltype(auto) { return std::forward<decltype(arg)>(arg); }; 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::_); 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 #endif //DLIB_IF_CONSTEXPR_H

View File

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

View File

@ -210,6 +210,24 @@ namespace dlib
template<class T> template<class T>
using is_complete_type = details::is_complete_type<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> 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> template<class F>
struct callable_traits; struct callable_traits : details::callable_traits<void, F> {};
/*! /*!
WHAT THIS OBJECT REPRESENTS WHAT THIS OBJECT REPRESENTS
This is a type trait for callable types like function pointers, functors and lambdas. This is a type trait for callable types.
It provides the following 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 return_type : the return type of the callable object
args : a parameter pack packaged in a types_<> meta container containing args : a parameter pack packaged in a types_<> meta container containing
all the function argument types all the function argument types
It also provides the following static members: It also provides the following static members:
nargs : the number of function arguments 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: 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>::return_type == R
callable_traits<F>::args == types_<T1,T2,T3> callable_traits<F>::args == types_<T1,T2,T3>
callable_traits<F>::nargs == 3 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> template<class Callable>
using callable_args = typename callable_traits<Callable>::args; using callable_args = typename callable_traits<Callable>::args;
@ -320,6 +359,9 @@ namespace dlib
template<class Callable> template<class Callable>
using callable_return = typename callable_traits<Callable>::return_type; using callable_return = typename callable_traits<Callable>::return_type;
template<class F>
using is_callable = std::integral_constant<bool, callable_traits<F>::is_callable>;
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
} }