IsCallable.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <type_traits>
7 
8 #include "Utilities/TypeTraits.hpp"
9 
10 namespace tt {
11 // @{
12 /// \ingroup TypeTraitsGroup
13 /// \brief Check if a type `T` is callable, i.e. `T(Args...)` is evaluable.
14 ///
15 /// \details
16 /// Inherits from std::true_type if `TT` has the call operator, operator()
17 /// defined with arguments `TArgs...`, otherwise inherits from std::false_type.
18 ///
19 /// \usage
20 /// For any type `TT` and types `TArgs_i`,
21 /// \code
22 /// using result = tt::is_callable<TT, TArgs_0, TArgs_1, TArgs_2>;
23 /// \endcode
24 ///
25 /// \metareturns
26 /// cpp17::bool_constant
27 ///
28 /// \semantics
29 /// If the type `TT` defines operator() with arguments `TArgs...`, then
30 /// \code
31 /// typename result::type = std::true_type;
32 /// \endcode
33 /// otherwise
34 /// \code
35 /// typename result::type = std::false_type;
36 /// \endcode
37 ///
38 /// \example
39 /// \snippet Test_IsCallable.cpp is_callable_example
40 /// \see std::is_callable
41 /// \tparam TT the class to check
42 /// \tparam TArgs the args passed to operator()
43 template <typename TT, typename... TArgs>
44 class is_callable {
45  // The reason we have private before public here is that we have static member
46  // functions and since this is meant to be a super lightweight helper class
47  // it's better to break convention than increase code size.
48  private:
49  /// \cond
50  // We pass an int here to disambiguate the two possible templates and have the
51  // compiler prefer the first one. If it cannot be used because there's no
52  // call operator, then it uses the second one.
53  template <typename T, typename... Args>
54  static auto test_callable(int) noexcept
55  -> decltype(std::declval<T>()(std::declval<Args>()...), std::true_type());
56 
57  template <typename, typename...>
58  static auto test_callable(...) noexcept -> std::false_type;
59  /// \endcond
60 
61  public:
62  /// `true` if callable, `false` otherwise
63  static constexpr bool value = decltype(test_callable<TT, TArgs...>(0))::value;
64  /// `std::true_type` if callable, `std::false_type` otherwise
66 };
67 /// \see is_callable
68 template <typename T, typename... Args>
69 constexpr bool is_callable_v = is_callable<T, Args...>::value;
70 
71 /// \see is_callable
72 template <typename T, typename... Args>
73 using is_callable_t = typename is_callable<T, Args...>::type;
74 // @}
75 } // namespace tt
Check if a type T is callable, i.e. T(Args...) is evaluable.
Definition: IsCallable.hpp:44
std::integral_constant< bool, value > type
std::true_type if callable, std::false_type otherwise
Definition: IsCallable.hpp:65
typename is_callable< T, Args... >::type is_callable_t
Definition: IsCallable.hpp:73
A collection of useful type traits.
Definition: TensorExpression.hpp:113
constexpr bool is_callable_v
Definition: IsCallable.hpp:69
static constexpr bool value
true if callable, false otherwise
Definition: IsCallable.hpp:63