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_ca
I use the following well known approach based on SFINAE:
#define TYPE_SUPPORTS(ClassName, Expr) \
template<typename U> \
struct ClassName \
{ \
private: \
template<typename> \
static constexpr std::false_type test(...); \
\
template<typename T = U> \
static decltype((Expr), std::true_type{}) test(int) ; \
\
public: \
static constexpr bool value = decltype(test<U>(0))::value; \
};
The main purpose of the macro is to simplify adding type checks. The macro defines a struct that allows you to do an arbitrary check for a type T
.
As an example, to check that std::begin()
can be called for a type:
namespace detail
{
TYPE_SUPPORTS(SupportsBegin, std::begin(std::declval<T>()))
}
template<typename T>
constexpr bool supportsBegin()
{
return detail::SupportsBegin<T>::value;
}
Of course, the detail
namespace and function wrapper are all syntactic sugar, but improve the syntax a bit on the caller side.
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 {};
No, it's pretty much the same way. More or less. Implementations vary, though you could replace some of the metafunctions used internally by that implementation with standard library traits. But there's no simple way of detecting if you can invoke a function on some type given some set of arguments.
That's for concepts (PDF).
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-