Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 ways of finding if a type has member function or supports operator?

Tags:

c++

c++11

There is a (seemingly) nice C++03 way of finding out if a type has a member function or operator:

https://github.com/jaredhoberock/is_call_possible/blob/master/is_call_possible.hpp

Is there no modern C++11 way to do this? It would be better not having to include any external code and use only the standard.

like image 845
tmppp Avatar asked Jun 19 '13 21:06

tmppp


2 Answers

C++ 11 adds a new trick, which I often jokingly call "CFINAE" (compilation failure is not an error).

It makes use of the decltype operator and the regular properties of SFINAE.

Consider the following function:

template <typename X, typename Y>
static auto check(X& x, Y& y) -> decltype(x >> y);

It will be considered during overloading only if X and Y are types for which the shift operator is defined. Add a regular catch-all overload for check and you have a mechanism to test whether an arbitrary expression can be compiled.

And indeed, this is the principle developed in the experimental Origin library by Andrew Sutton (one of the authors of the Concepts Lite proposal). In fact, my example is taken straight from here to implement the Streamable concept.

I recommend the following presentation from GoingNative 2012 by Andrew Sutton and Bjarne Stroustrup where they give an introduction to the new take on concepts and the Origin library:

http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/A-Concept-Design-for-C-

like image 113
zah Avatar answered Oct 22 '22 16:10

zah


This works with all test cases given in the GitHub (Demo: http://ideone.com/ZLGp4R):

#include <type_traits>

template <typename C, typename F, typename = void>
struct is_call_possible : public std::false_type {};

template <typename C, typename R, typename... A>
struct is_call_possible<C, R(A...),
    typename std::enable_if<
        std::is_same<R, void>::value ||
        std::is_convertible<decltype(
            std::declval<C>().operator()(std::declval<A>()...)
            //                ^^^^^^^^^^ replace this with the member you need.
        ), R>::value
    >::type
> : public std::true_type {};
like image 34
kennytm Avatar answered Oct 22 '22 17:10

kennytm