#include <functional> // std::function, std::bind (for example)
#include <iostream> // std::cout, std::endl, std::boolalpha (for example)
#include <utility> // std::declval (for example)
#include <type_traits> // std::remove_reference_t, std::true_type, std::false_type (for implementation)
// is_callable IMPLEMENTATION
template<typename T, typename U = void>
struct is_callable
{
static bool const constexpr value = std::conditional_t<
std::is_class<std::remove_reference_t<T>>::value,
is_callable<std::remove_reference_t<T>, int>, std::false_type>::value;
};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(*)(Args...), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(&)(Args...), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(*)(Args......), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(&)(Args......), U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)volatile, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const volatile, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)volatile, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const volatile, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)&, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)volatile&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const volatile&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)&, U> : std::true_type {};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)volatile&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const volatile&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)volatile&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args...)const volatile&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)volatile&&, U> : std::true_type{};
template<typename T, typename U, typename ...Args>
struct is_callable<T(Args......)const volatile&&, U> : std::true_type{};
template<typename T>
struct is_callable<T, int>
{
private:
using YesType = char(&)[1];
using NoType = char(&)[2];
struct Fallback { void operator()(); };
struct Derived : T, Fallback {};
template<typename U, U>
struct Check;
template<typename>
static YesType Test(...);
template<typename C>
static NoType Test(Check<void (Fallback::*)(), &C::operator()>*);
public:
static bool const constexpr value = sizeof(Test<Derived>(0)) == sizeof(YesType);
};
// END is_callable IMPLEMENTATION
struct Callable { void operator()() {} };
struct PrivateCallable
{
private:
void operator()(int) {}
double operator()(bool, char*) {}
PrivateCallable(int, int) {}
};
struct NotCallable
{
void mFoo() {}
void mConstFoo() const {}
int mInt;
};
int foo() {}
template<typename ...Args>
void bar(Args &&...args, ...) {}
enum WeakTypeEnum {};
enum class StrongTypeEnum {};
int main(int, char**) noexcept
{
auto pfoo = &foo;
int (&rfoo)() = foo;
auto bfoo = std::bind(&foo);
NotCallable nc;
auto bmfoo = std::bind(&NotCallable::mFoo, &nc);
auto bmcfoo = std::bind(&NotCallable::mConstFoo, &nc);
auto lamb = [](char**) -> decltype(auto)
{
return "Hello World!";
};
std::cout << std::endl << std::boolalpha
<< "SCALARS" << std::endl
<< "int: " << is_callable<int>::value << std::endl
<< "long double: " << is_callable<long double>::value << std::endl
<< "int*: " << is_callable<int*>::value << std::endl
<< "int const*: " << is_callable<int const*>::value << std::endl
<< "int const *const: " << is_callable<int const *const>::value << std::endl
<< "WeakTypeEnum: " << is_callable<WeakTypeEnum>::value << std::endl
<< "StrongTypeEnum: " << is_callable<StrongTypeEnum>::value << std::endl
<< "NotCallable::*: " << is_callable<decltype(&NotCallable::mInt)>::value << std::endl
<< "nullptr_t: " << is_callable<decltype(nullptr)>::value << std::endl
<< "Callable*: " << is_callable<Callable*>::value << std::endl
<< std::endl
<< "REFERENCES" << std::endl
<< "int&: " << is_callable<int&>::value << std::endl
<< "int const&: " << is_callable<int const&>::value << std::endl
<< "NotCallable&: " << is_callable<NotCallable&>::value << std::endl
<< "NotCallable const&: " << is_callable<NotCallable const&>::value << std::endl
<< "Callable&: " << is_callable<Callable&>::value << std::endl
<< "Callable const&: " << is_callable<Callable const&>::value << std::endl
<< "function reference: " << is_callable<decltype(rfoo)>::value << std::endl
<< std::endl
<< "FUNCTIONS" << std::endl
<< "function (no params): " << is_callable<int()>::value << std::endl
<< "function (params): " << is_callable<double(char*)>::value << std::endl
<< "function (const): " << is_callable<void(bool) const>::value << std::endl
<< "function (ref qualifier): " << is_callable<void(bool)&>::value << std::endl
<< "function (rvalue ref qualifier): " << is_callable<void(bool)&&>::value << std::endl
<< "function (variadic): " << is_callable<void(...)>::value << std::endl
<< "templated variadic function: " << is_callable<decltype(bar<>)>::value << std::endl
<< "function pointer: " << is_callable<decltype(pfoo)>::value << std::endl
<< "member function pointer: " << is_callable<decltype(&NotCallable::mFoo)>::value << std::endl
<< "const member function pointer: " << is_callable<decltype(&NotCallable::mConstFoo)>::value << std::endl
<< "bind expression (free function): " << is_callable<decltype(bfoo)>::value << std::endl
<< "bind expression (member function): " << is_callable<decltype(bmfoo)>::value << std::endl
<< "bind expression (const member function): " << is_callable<decltype(bmcfoo)>::value << std::endl
<< "functor: " << is_callable<Callable>::value << std::endl
<< "private functor: " << is_callable<PrivateCallable>::value << std::endl
<< "std::function: " << is_callable<std::function<int()>>::value << std::endl
<< "lambda: " << is_callable<decltype(lamb)>::value << std::endl;
return 0;
}