Search code examples
c++c++17template-meta-programmingfunctortype-traits

Creating a type trait to detect functors in C++


Considering the following custom definition:

A functor is a (possibly final) (possibly union) class with a publicly overloaded operator().

How to define a type trait:

template <class T> 
struct is_functor {
    static constexpr bool value = /* something */
};

template <class T>
inline constexpr bool is_functor_v = is_functor<T>::value;

that evalues to true when T is such a functor, and false otherwise, in standard C++17?


Solution

  • Here is an attempt (non-working counter examples are welcome)

    struct _argument {
        template <class T> constexpr operator T&() const& noexcept;
        template <class T> constexpr operator T&&() const&& noexcept;
    };
    
    template <class F, class Args = std::tuple<>, std::size_t N = 128, class = void>
    struct _min_arity {};
    
    template <class F, template <class...> class T, class... Args, std::size_t N>
    struct _min_arity<F, T<Args...>, N, std::enable_if_t<sizeof...(Args) <= N>>
    : std::conditional_t<
        std::is_invocable_v<F, Args...>,
        std::integral_constant<std::size_t, sizeof...(Args)>,
        _min_arity<F, std::tuple<Args..., _argument>, N>
    > {};
    
    template <class F, class = void, class = void>
    struct _has_function_call_operator
    : std::false_type
    {};
    
    template <class F>
    struct _has_function_call_operator<
        F,
        std::enable_if_t<std::is_class_v<F> || std::is_union_v<F>>,
        std::void_t<decltype(_min_arity<F>::value)>
    >
    : std::true_type
    {};
    
    template <class T>
    struct is_functor
    : std::bool_constant<_has_function_call_operator<T>::value>
    {};