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