Search code examples
c++variadic-templatesc++17sfinaevoid-t

Mixing void_t and variadic templates?


Consider the following code:

template <class F, class... Args, class = std::void_t<>>
struct is_invokable
: std::false_type {};
template <class F, class... Args>
struct is_invokable<F, Args..., std::void_t<std::invoke_result_t<F, Args...>>>
: std::true_type {};

The goal is to have a trait that is able to tell whether a callable of type F is invokable with arguments of type Args....

However, it fails to compile because:

error: parameter pack 'Args' must be at the end of the template parameter list

What is the (elegant) way to do this in C++17?


Solution

  • namespace details {
      template <class F, class, class... Args>
      struct is_invokable : std::false_type {};
      template <class F, class... Args>
      struct is_invokable<F, std::void_t<std::invoke_result_t<F, Args...>>, Args...>
      : std::true_type {};
    }
    template <class F, class... Args>
    using is_invokable=typename ::details::is_invokable<F, void, Args...>::type;