jlanik
jlanik

Reputation: 939

Can std::is_invocable be emulated within C++11?

I'd like to use std::is_invocable, but it is available only since C++17, and we are using C++11 Standard.

Is there any way to emulate the functionality using C++11?

Upvotes: 20

Views: 4059

Answers (2)

LoS
LoS

Reputation: 1833

The is_invocable type trait is true if the type T can be invoked with the variadic number of arguments Args.

To implement the condition, it is sufficient to verify whether the expression std::bind(std::declval<T>(), std::declval<Args>()...) is well-formed.

Example:

namespace detail {
  template <typename, typename, typename = void>
  struct is_invocable
   : std::false_type {};

  template <typename T, typename ...Args>
  struct is_invocable<T, std::tuple<Args...>, std::void_t<decltype(std::bind(std::declval<T>(), std::declval<Args>()...))>>
   : std::true_type {};
}

template <typename T, typename ...Args>
struct is_invocable
 : detail::is_invocable<T, std::tuple<Args...>> {};

It is important to note that, to realize the type trait, it is necessary to implement a little trick. Indeed, the implementation requires to default the last template parameter to void, but it does not allow to insert a variadic number of template parameters. The adopted solution exploits a helper structure that must be specialized with the variadic pack and then passed as a single template argument. In this case, std::tuple has been used for simplicity. The partial specialization of the type trait tries to deduce the template arguments of the specialized helper structure, extracting the pack again.

Even if the std::void_t type trait is available only since C++17, it can be implemented from scratch.

Example:

template <typename...>
using void_t = void;

Upvotes: 3

Mohit
Mohit

Reputation: 1305

You can try this implementation:) Taken from boost C++ libraries. I've tested it with VS2017 with standard C++14.

template <typename F, typename... Args>
struct is_invocable :
    std::is_constructible<
        std::function<void(Args ...)>,
        std::reference_wrapper<typename std::remove_reference<F>::type>
    >
{
};

template <typename R, typename F, typename... Args>
struct is_invocable_r :
    std::is_constructible<
        std::function<R(Args ...)>,
        std::reference_wrapper<typename std::remove_reference<F>::type>
    >
{
};

Upvotes: 26

Related Questions