template <typename Model> struct MyConcept { // We declare a type. typedef typename Model::SomeType SomeType; typedef typename Model::ReturnType ReturnType; #ifdef GEN_DOC //We declare the needed functions ReturnType operator()(SomeType&, int); #else typedef void static_check; static_assert(std::is_same<ReturnType, std::declval<SomeType&>()(0)>::value, "operator()(SomeType&, int) does not return ReturnType"); #endif }; template <typename T> struct MyModel { typedef void NoModel; };
struct A { int operator()(int) { return 0; } }; template <> struct MyModel<A> { struct Model { typedef A SomeType; typedef int RetType; }; };
template <typename T, typename Model = MyModel<T>::Model> void foo(T) { //We have a model, but we need to require this model to check. typedef typename Model::static_check require; //... }
Or for a class:
template <typename T> struct Foo { typedef typename MyModel<T>::Model::static_check require; //... };
In case it is possible to know automatically a model, then we can do as follow.
template <typename T, bool = is_callable_with<T&, int>::value> struct MyModel; template <typename T> struct MyModel<T, false> { typedef void NoModel; }; template <typename T> struct MyModel<T, true> { struct Model { typedef A SomeType; typedef decltype(std::declval<T&>()(std::declval<int>())) RetType; }; };
TODO