Following may help, it checks complete signatures:
#include <cstdint>
#include <type_traits>
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static std::uint8_t check(helper<signature, &funcName>*); \
template<typename T> static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
}
DEFINE_HAS_SIGNATURE(has_getS, T::getS, size_t (T::*)() const);
DEFINE_HAS_SIGNATURE(has_getA, T::getA, size_t (T::*)() const);
DEFINE_HAS_SIGNATURE(has_getTransitionProbability, T::getTransitionProbability, double (T::*)(size_t, size_t, size_t) const);
DEFINE_HAS_SIGNATURE(has_getExpectedReward, T::getExpectedReward, double (T::*)(size_t, size_t, size_t) const);
template <typename T>
struct is_model :
std::conditional<has_getS<T>::value
&& has_getA<T>::value
&& has_getTransitionProbability<T>::value
&& has_getExpectedReward<T>::value,
std::true_type, std::false_type>::type
{};
Test it:
struct Model {
size_t getS() const { return 0;}
size_t getA() const { return 0;}
double getTransitionProbability(size_t, size_t, size_t) const {return 0.0;}
double getExpectedReward(size_t, size_t, size_t) const {return 0.0;}
};
static_assert(is_model<Model>::value, "it should respect contract");
static_assert(!is_model<int>::value, "it shouldn't respect contract");