This is a kind of concept check.

We have a type predicate for the type T that saysif the type T is a concept X.

It will be, if the type T is derived from X, or if we explicitly say that.


#include <type_traits>
#include <iostream>


struct shape_concept {};
struct circle_concept : public shape_concept {};
struct square_concept : public shape_concept {};



//By default check if Concept is base of T
template<class T, class Concept>
struct is_concept_model : public std::is_base_of<Concept, T> {};


//Formula for circle_concept
template<class T>
typename std::enable_if<is_concept_model<T, circle_concept>::value, double>::type
Area(const T& o)
{
    const double pi = 3.14;
    return pi * o.radius() * o.radius();
}

//Formula for square_concept
template<class T>
typename std::enable_if<is_concept_model<T, square_concept>::value, double>::type
Area(const T& o)
{
    return o.side() * o.side();
}

//Error if T is not a shape_concept model
template<class T>
typename std::enable_if<!is_concept_model<T, shape_concept>::value, double>::type
Area(const T& o)
{
    static_assert(false, "type T must map shape_concept");
    return 0;
}

struct MyCircle1 : public circle_concept
{
    double radius() const
    {
        return 1.5;
    }
};

struct MyCircle2
{
    double radius() const
    {
        return 2.0;
    }
};

//We explicitly will say that MyCircle2 is a model of circle_concept 
//and that MyCircle2 is a model of shape_concept should be automatic!
template<> struct is_concept_model<MyCircle2, circle_concept> : public std::true_type {};
template<> struct is_concept_model<MyCircle2, shape_concept> : public std::true_type{};

struct MySquare1 : public square_concept
{
    double side() const
    {
        return 2.0;
    }
};

struct MySquare2
{    
};

int main()
{
    MySquare1 s1;
    MySquare2 s2;
    MyCircle1 c1;
    MyCircle2 c2;
    std::cout << Area(s1) << std::endl;
    std::cout << Area(c1) << std::endl;
    std::cout << Area(c2) << std::endl;
    // std::cout << Area(s2) << std::endl;
}