Смешивать шаблоны void_t и variadic?

Рассмотрим следующий код:

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 {};

Цель состоит в том, чтобы иметь черту, способную определить, является ли вызываемый тип F вызывается с аргументами типа Args...,

Тем не менее, он не может скомпилировать, потому что:

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

Каков (элегантный) способ сделать это в C ++ 17?

4

Решение

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;
6

Другие решения

Я предлагаю помощника struct (is_invokable_h) и использование std::tuple обернуть Args...

Что-то вроде

#include <type_traits>
#include <utility>

template <typename, typename, typename = void>
struct is_invokable_h : std::false_type
{};

template <typename F, typename ... Args>
struct is_invokable_h<F, std::tuple<Args...>,
std::void_t<std::invoke_result_t<F, Args...>>>
: std::true_type
{};

template <typename F, typename ... Args>
struct is_invokable : is_invokable_h<F, std::tuple<Args...>>
{};

int foo (int)
{ return 0; }

int main()
{
static_assert( true  == is_invokable<decltype(foo), int>{} );
static_assert( false == is_invokable<decltype(foo), int, int>{} );
}
1

По вопросам рекламы [email protected]