Mixing void_t and variadic templates?
Asked Answered
N

2

6

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?

Normalie answered 19/12, 2017 at 22:31 Comment(2)
Well, where else other than the end can you put void? Put it there.Uppity
Huh. I didn’t realize that types required the pack to be in the final position. Functions don’t, if you give default arguments or they can be deduced.Ulbricht
I
8
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;
Interim answered 19/12, 2017 at 23:10 Comment(0)
T
1

I propose an helper struct (is_invokable_h) and the use of std::tuple to wrap the Args...

Something like

#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>{} );
 }
Teletype answered 19/12, 2017 at 22:42 Comment(2)
Or std::is_invocable introduced by C++17.Goran
You're right: or std::is_invocable. But was my intention show a possible way to bypass the problem of the default template type after a template variadic list.Teletype

© 2022 - 2024 — McMap. All rights reserved.