问题描述:

Can I write a trait metafunction to figure out if a type is a functor or not?

There are tons of code which can check functor using SFINAE of `decltype(&T::operator())`

, for instance,

`template<class T>`

struct is_functor {

template<class F>

static auto test(decltype(&F::operator())) -> std::true_type;

template<class F>

static auto test(...) -> std::false_type;

static constexpr bool value = decltype(test<T>(0))::value;

};

However, this doesn't work for generic lambda because generic lambda

's `operator()`

is a template function.

There are some code for limited case for generic lambda version which make some constraints on the argument type of generic lambda. For instance, an answer here(http://stackoverflow.com/a/5117641/2580815) won't work if lambda expression contains any expression which cannot be valid for `int`

type such as member access operation.

I don't need any generality for arity. In fact, I only need to know a type can be a functor which accepts only one parameter.

How can I implement my `is_functor`

?

Use case:

I'm trying to validate if given parameter is a functor or not for a template function, that is, I want to like some overloaded tempalte functions, for instance:

`template<class F, class = enable_if_t<is_functor<std::decay_t<F>>::value>>`

auto make_func(F &&f) { return std::forward<F>(f); }

template<class F, class = enable_if_t<!is_functor<std::decay_t<F>>::value>>

auto make_func(F &&f) { return [f=std::forward<F>(f)] (auto&&) { return f; }; }

There is no proper way of doing this *(at least until we get static reflection)*. The best you can do is check that an object is *callable* with a certain degree of confidence:

Try getting its

`operator()`

address. If it fails, then the object may either be*non-callable*or its`operator()`

could be overloaded/templated.Try calling the object with a dummy

`any_type`

instance that provides an interface for commonly used function. This might help you deduce its arity.If everything fails, force the user to somehow help the arity deduction or manually specify the arity.

One way you could approach this is by having a `deduced_arity`

set of tags:

```
namespace deduced_arity
{
template <std::size_t TS>
struct deducible_t : std::integral_constant<std::size_t, TS>
{
};
struct undeducible_t
{
};
constexpr undeducible_t undeducible{};
constexpr deducible_t<1> unary{};
}
```

You will also need some sort of `function_traits`

implementation that will statically tell you the exact arity of a *function object*. This can be found in Boost.

Then you also need an implementation of `any_type`

.

Afterwards, you can use something like the following type trait to check whether or not a *function object* **may** be overloaded, using the *detection idiom*:

```
template <typename T>
using is_not_overloaded_impl = decltype(&T::operator());
template <typename T>
using is_not_overloaded =
std::experimental::is_detected<is_not_overloaded_impl, T>;
```

Then you can use a chain of `if constexpr(...)`

*(or any other compile-time branching mechanism)* to make a good guess - example:

```
if constexpr(is_not_overloaded<T>{})
{
// use `function_traits` here
}
else if constexpr(std::is_callable<T(any_type)>{})
{
return deduced_arity::unary;
}
else if constexpr(/* user manually marked arity */)
{
/* deal with user-defined deduction helpers */
}
else
{
return deduced_arity::undeducible;
}
```

Reusing most of the code from my answer to a twin question (that one about finding a function's arity):

```
template <class, std::size_t N, class = std::make_index_sequence<N>, class = void_t<>>
struct CanCall : std::false_type { };
template <class F, std::size_t N, std::size_t... Idx>
struct CanCall<
F, N,
std::index_sequence<Idx...>,
void_t<decltype(std::declval<F>()((Idx, std::declval<Any const&&>())...))>
> : std::true_type { };
```

`CanCall<F, N>`

will return whether `F`

is callable with `N`

parameters of arbitrary type. The Any helper type has templated implicit conversion operators that allows it to morph into any desired parameter type.

Then, for your specific use-case (unary functors):

```
template <class F>
struct IsUnaryFunctor : CanCall<F, 1u> { };
```

See it live on Coliru