Я думаю о концепциях как о мета-интерфейсе. Они классифицируют типы после своих способностей. Следующая версия C++ предоставляет собственные концепции. Я не понял этого, пока не натолкнулся на концепции C++ 1x и как они позволяют объединять разные, но несвязанные типы. Представьте, что у вас есть интерфейс Range
. Вы можете моделировать это двумя способами. Одним из них является соотношение подтип:
class Range {
virtual Iterator * begin() = 0;
virtual Iterator * end() = 0;
virtual size_t size() = 0;
};
Конечно, каждый класс, производный от, который реализует интерфейс Range и может использоваться с функциями. Но теперь вы видите, что он ограничен. Как насчет массива? Это тоже диапазон!
T t[N];
begin() => t
end() => t + size()
size() => N
К сожалению, вы не можете получить массив из этого класса Range, реализующего этот интерфейс.Вам нужен дополнительный метод (перегрузка). А как насчет сторонних контейнеров? Пользователь вашей библиотеки может захотеть использовать свои контейнеры вместе с вашими функциями. Но он не может изменить определение своих контейнеров. Здесь понятия вступают в игру:
auto concept Range<typename T> {
typename iterator;
iterator T::begin();
iterator T::end();
size_t T::size();
}
Теперь, вы говорите что-то о поддерживаемых операциях некоторого типа, которые могут быть выполнены, если T
имеют соответствующие функции-членов. В вашей библиотеке вы должны написать функцию generic. Это позволяет принимать любые типы , пока поддерживает необходимые операции:
template<Range R>
void assign(R const& r) {
... iterate from r.begin() to r.end().
}
Это отличный вид взаимозаменяемости. Любой тип подходит к законопроекту, который придерживается концепции, а не только те типы, которые активно реализуют некоторый интерфейс. Следующий стандарт C++ продвигается дальше: он определяет концепцию Container
, которая будет соответствовать простым массивам (по какой-то причине концепция map, которая определяет, как какой-то тип подходит для какой-то концепции) и другие, существующие стандартные контейнеры.
Причина, по которой я это делаю, заключается в том, что у меня есть шаблон с шаблонами, где сами контейнеры имеют иерархические отношения. Я хотел бы написать алгоритмы, которые используют эти контейнеры, не заботясь о том, какой конкретный контейнер он есть. Кроме того, некоторые алгоритмы выиграют от знания того, что тип шаблона удовлетворял определенным понятиям (например, Comparable).
На самом деле вы можете сделать оба с шаблонами. Вы можете продолжать использовать иерархические отношения для совместного использования кода, а затем писать алгоритмы в общем виде. Например, чтобы сообщить, что ваш контейнер сопоставим. Это как стандартный произвольный доступ вперед/назад/выход/вход категория итераторов реализованы:
// 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
Это разумный простой способ сделать это, на самом деле. Теперь вы можете вызвать функцию, и она перейдет к правильной реализации.
template<typename Container>
void takesAdvantage(Container const& c) {
takesAdvantageOfCompare(c, typename Container::comparator_kind());
}
// implementation for basic_comparable containers
template<typename Container>
void takesAdvantage(Container const& c, basic_comparable) {
...
}
// implementation for not_comparable containers
template<typename Container>
void takesAdvantage(Container const& c, not_comparable) {
...
}
На самом деле существуют различные методы, которые могут быть использованы для его реализации. Другой способ - использовать boost::enable_if
для включения или отключения различных реализаций каждый раз.
C++ 1x? Означает ли это, что они отказались от выпуска нового стандарта в этом десятилетии или вы говорите о будущей разработке на C++? – jpalecek
http://www.research.att.com/~bs/C++0xFAQ.html#concepts – jmucchiello
jpalecek, они хотят выпустить его в 2010 году. У меня есть привычка называть его C++ 1x :) –