Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find out whether a C++ object is callable

Is it possible to write a type trait, say is_callable<T> which tells if an object has an operator() defined? It is easy if the arguments to the call operator are known in advance, but not in the general case. I want the trait to return true if and only if there is at least one overloaded call operator defined.

This question is related and has a good answer, but it doesn't work on all types (only on int-convertible types). Also, std::is_function works, but only on proper C++ functions, not on functors. I'm looking for a more general solution.

like image 528
Antoine Avatar asked Mar 13 '13 18:03

Antoine


People also ask

What is callable in C?

A Callable type is a type for which the INVOKE operation (used by, e.g., std::function, std::bind, and std::thread::thread) is applicable. The INVOKE operation may be performed explicitly using the library function std::invoke. (since C++17)

What are callable objects C++?

A callable object is something that can be called like a function, with the syntax object() or object(args) ; that is, a function pointer, or an object of a class type that overloads operator() . The overload of operator() in your class makes it callable.

What makes a function callable?

A callable object is an object which can be used and behaves like a function but might not be a function. By using the __call__ method it is possible to define classes in a way that the instances will be callable objects. The __call__ method is called, if the instance is called "like a function", i.e. using brackets.


1 Answers

I think this trait does what you want. It detects operator() with any kind of signature even if it's overloaded and also if it's templatized:

template<typename T> struct is_callable { private:     typedef char(&yes)[1];     typedef char(&no)[2];      struct Fallback { void operator()(); };     struct Derived : T, Fallback { };      template<typename U, U> struct Check;      template<typename>     static yes test(...);      template<typename C>     static no test(Check<void (Fallback::*)(), &C::operator()>*);  public:     static const bool value = sizeof(test<Derived>(0)) == sizeof(yes); }; 

The principle is based on Member Detector idiom. As it is, it will fail to compile if you pass it a non-class type, but that shouldn't be hard to fix, I just left it out for brevity. You can also extend it to report true for functions.

Of course it doesn't give you any info about the signature(s) of operator() whatsoever, but I believe that's not what you asked for, right?

EDIT for Klaim:

It's simple enough to make it work (return false) with non-class types. If you rename the above class to is_callable_impl, you can write this, for example:

template<typename T> struct is_callable     : std::conditional<         std::is_class<T>::value,         is_callable_impl<T>,         std::false_type     >::type { }; 
like image 119
jrok Avatar answered Sep 20 '22 04:09

jrok