I think of concepts as a meta-interface. They classify types after their abilities. The next version of C ++ provides its own concepts. I did not understand this until I came across the concepts of C ++ 1x and how they allow you to combine different, but unrelated types. Imagine you have a Range interface. You can model this in two ways. One of them is the subtype relation:
class Range { virtual Iterator * begin() = 0; virtual Iterator * end() = 0; virtual size_t size() = 0; };
Of course, every class derived from this implements the Range interface and can be used with your functions. But now you see that it is limited. How about an array? This is also a range!
T t[N]; begin() => t end() => t + size() size() => N
Unfortunately, you cannot get an array from this Range class that implements this interface. You need an additional method (overload). What about third-party containers? Your library user may want to use their containers along with your functions. But he cannot change the definition of his containers. This is where the concepts come into play:
auto concept Range<typename T> { typename iterator; iterator T::begin(); iterator T::end(); size_t T::size(); }
Now you are saying something about supported operations of some type that can be performed if T has corresponding member functions. You must write a generic function in your library. This allows you to accept any type if it supports the required operations:
template<Range R> void assign(R const& r) { ... iterate from r.begin() to r.end(). }
This is a great kind of interchangeability. Any type will correspond to a bill that adheres to the concept, and not just those types that actively implement a certain interface. The next C ++ standard goes further: it defines the concept of Container , which will correspond to simple arrays (using some kind of hidden conceptual map, which determines how some type is suitable for some concept) and other existing standard containers.
The reason I do this is because I have a template with templates where the containers themselves have hierarchical relationships. I would like to write the algorithms that these containers use without caring about which specific container it is. In addition, it would be useful for some algorithms to know that the type of the template satisfies certain concepts (for example, Comparable).
In fact, you can use both templates. You can continue to use hierarchical relationships to share code, and then write algorithms in a general way. For example, to indicate that your container is comparable. This is similar to the standard random access / direct / output / input iterator categories:
// tag types for the comparator cagetory struct not_comparable { }; struct basic_comparable : not_comparable { }; template<typename T> class MyVector : public BasicContainer<T> { typedef basic_comparable comparator_kind; }; /* Container concept */ T::comparator_kind: comparator category
This is a reasonable, simple way to do this, in fact. Now you can call the function and it will go to the correct implementation.
template<typename Container> void takesAdvantage(Container const& c) { takesAdvantageOfCompare(c, typename Container::comparator_kind()); }
There are actually different methods that you can use to implement it. Another way is to use boost::enable_if to enable or disable different implementations each time.