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?
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?
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>
>
{
};
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;
std::is_invocable
in the case of function objects Demo. A final nitpick is that I'd probably prefer an alias instead of inheritance in the actual trait. E.g., using is_invocable = detail::is_invocable<T, std::tuple<Args...>>
–
Gratia std::bind
, but the OP explicitly requires C++11. About the inheritance - aliasing, I have chosen the first one for consistency with other type traits (consistency across implementation of type traits in my posts). –
Gustie operator()
defined. –
Gratia © 2022 - 2024 — McMap. All rights reserved.
std::__is_invocable
? – Valorizestd:__is_invocable
is not part of C++11, nor of any other version of the C++ standard. It looks like an interanal detail for a particular library implementation. – Roxieroxine