Пример С++ для этого класса
Я не использовал расширенные возможности С++ некоторое время и обновляю свои знания на С++.
Сказав это, концепция черт и программ, основанных на политике, была чем-то, что мне никогда не удавалось обойти.
Я хочу изменить это. Я пишу общий контейнер. Я хочу применить политику, согласно которой контейнер будет хранить только классы, которые происходят из определенного базового класса. Это происходит потому, что контейнер возвращает недопустимый объект (вместо метания), когда делается попытка получить доступ к элементу вне границ вектора.
template <class T>
class GenericContainer
{
private:
typedef std::vector<T> TypeVect;
void addElement(const T& elem);
TypeVect m_elems;
public:
unsigned int size() const;
T& elementAt(const unsigned int pos);
const T elementAt(const unsigned int pos) const;
};
Как я могу использовать черты, чтобы ограничить этот общий контейнер содержащими только подклассы класса 'ContainerItem' say?
Ответы
Ответ 1
Вы можете использовать небольшой шаблон IsDerivedFrom
, который может быть создан только в том случае, если данный тип 'D' наследует другой тип 'B' (эта реализация была взята из хорошая статья из статьи "Неделя" :
template<typename D, typename B>
class IsDerivedFrom
{
static void Constraints(D* p)
{
B* pb = p; // this line only works if 'D' inherits 'B'
pb = p; // suppress warnings about unused variables
}
protected:
IsDerivedFrom() { void(*p)(D*) = Constraints; }
};
// Force it to fail in the case where B is void
template<typename D>
class IsDerivedFrom<D, void>
{
IsDerivedFrom() { char* p = (int*)0; /* error */ }
};
Теперь вы можете просто создать экземпляр шаблона IsDerivedFrom
, используя наследование:
template <class T>
class GenericContainer : public IsDerivedFrom<T, ContainerItem>
{
...
};
Этот код компилируется, если T
наследует ContainerItem
.
Ответ 2
Вы можете принудительно выполнить это с помощью boost:: mpl для подтверждения во время компиляции, которое тип наследует от базы.
"Ролл свой собственный" довольно прост:
template <typename D, typename B>
class is_derived_from {
class No { };
class Yes { No no[2]; };
static Yes Test(B*);
static No Test(...);
public:
enum { inherits = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) };
static bool is_derived() { return inherits; }
};
Я думаю, что это исходило из GoTW изначально. Все, что вам нужно, это подходящий механизм утверждения (время компиляции, вероятно, лучше). Обычным трюком для этого является создание макроса, который делает массив с отрицательным размером, чтобы сбой assert или 1, чтобы передать его.
Ответ 3
Я думаю, что вы ищете концептуальную проверку. Это должно было быть встроено в С++ 0x, но оно было отложено. Библиотеки Boost содержат библиотеку для управления концепциями, но это далеко не синтаксическая конфета.
Боковое примечание: будьте осторожны с нарезкой объектов в контейнере. Если вы хотите, чтобы оба базовых и производных класса были сохранены в контейнере, используйте указатели вместо самих объектов.
Ответ 4
Типовые черты и программирование на основе политик - это разные темы. Типовые черты добавляют новую информацию о существующих типах и типах, которые не могут содержать дополнительную информацию (любой встроенный). Разработка на основе политик - это метод проектирования классов, чтобы вы могли собирать их различными способами для создания разных поведений; это своего рода шаблон состояния времени компиляции.