Reducing the use of std::result_of
to accomplish what you want might look like this:
template <class T, class, class... Args> struct callable: std::false_type { }; template <class T, class... Args> struct callable<T, decltype(std::result_of_t<T(Args...)>(), void()), Args...>:std::true_type { }; template <class F, class... Args> constexpr auto callable_v = callable<F, void, Args...>::value;
[live demo]
you need to remember that the type returned by result_of
is always the type of the result of the function that you pass to this type by type. For your sphina to work, you need a method to change this type to void in all possible situations. You can execute it using the trick with decltype ( decltype(std::result_of_t<T(Args...)>(), void())
).
Edit:
Develop a stream of comments about possible shortcomings of the solution. The type std::result_of_t<T(Args...)>
does not have to be equipped with a non-parametric default constructor, and therefore sfinae can cause a false negative callable_v
for a function that leads to such types. In the comments, I suggested a workaround for a problem that does not actually solve the problem or actually generates a new one:
decltype(std::declval<std::result_of_t<T(Args...)>*>(), void())
The intention of this code was to make sfinae work, as in the previously proposed solution, but in the case of non-constructive types, to create an easy-to-construct object (I thought) a pointer to this type ... In this discussion, I didnβt use βt consider types You cannot create a pointer to, for example, Recommendations. This again can be a workaround using some additional wrapper class:
decltype(std::declval<std::tuple<std::result_of_t<T(Args...)>>*>(), void())
or by decomposing the result type:
decltype(std::declval<std::decay_t<std::result_of_t<T(Args...)>>*>(), void())
but I think this is not worth it, and perhaps using void_t is actually a simpler solution:
template <class...> struct voider { using type = void; }; template <class... Args> using void_t = typename voider<Args...>::type; template <class T, class, class... Args> struct callable: std::false_type { }; template <class T, class... Args> struct callable<T, void_t<std::result_of_t<T(Args...)>>, Args...>:std::true_type { }; template <class F, class... Args> constexpr auto callable_v = callable<F, void, Args...>::value;
[live demo]