Using `void_t` to check if a class has a method with a specific signature
First, an id-expression naming a nonstatic member function can't be used as an unevaluated operand (such as the operand of decltype
). Moreover, you should check for whether the entire function call expression is well formed, not just whether there is a member called getCount
:
template< class, class = void >
struct hasGetCount : false_type { };
template< class T >
struct hasGetCount<T, VoidT<decltype(std::declval<T>().getCount())>>
: std::is_same<decltype(std::declval<T>().getCount()), int>::type { };
(Use declval<T&>
if you want to check that getCount()
can be called on an lvalue.)
If you just check for the existence of a getCount
member, then you get a hard error if a member with that name exists but isn't callable (e.g., a data member).
Although at this point you might as well consider just using something like
template< class T >
struct hasGetCount<T, std::enable_if_t<std::is_same<decltype(std::declval<T>().getCount()), int>::value>> : std::true_type { };
instead of writing the decltype
twice.
You could use void_t
to easily verify that the return type of getCount
is convertible to int
:
template< class, class = void >
struct hasGetCount : false_type { };
template< class T >
struct hasGetCount<T,
VoidT<
decltype(std::declval<int&>() = std::declval<T>().getCount())
>> : std::true_type {};
(Ideone live code)
Hopefully, by the time C++17 comes out, we'll be able to do this more easily with Concepts Lite:
template <typename T>
concept bool hasGetCount = requires (T t) {
{ t.getCount() } -> int;
};