Пример особенностей C ++ для этого класса - PullRequest
13 голосов
/ 21 января 2011

Я давно не пользовался расширенными возможностями C ++ и обновляю свои знания C ++. Сказав это, концепция черт и программирования, основанного на политике, была тем, что мне так и не удалось осознать.

Я хочу это изменить. Я пишу универсальный контейнер. Я хочу применить политику, согласно которой контейнер будет хранить только классы, производные от определенного базового класса. Это связано с тем, что контейнер возвращает недопустимый объект (вместо броска) при попытке получить доступ к элементу за пределами векторных границ.

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', скажем?

Ответы [ 4 ]

12 голосов
/ 21 января 2011

Вы можете использовать небольшой шаблон 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.

5 голосов
/ 21 января 2011

Вы можете применить это, используя boost :: mpl , чтобы утверждать во время компиляции, что тип наследуется от базы.

"Roll your own" довольно прост:

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.Все, что вам нужно, - это подходящий механизм подтверждения (время компиляции, вероятно, лучше).Обычный трюк для этого заключается в создании макроса, который делает массив с отрицательным размером для сбоя утверждения или 1 для его передачи.

3 голосов
/ 21 января 2011

Я думаю, вы ищете для проверки концепции.Это должно было быть встроено в C ++ 0x, но оно было отложено.Библиотеки Boost содержат библиотеку для управления концепциями, но это далеко не конфетка синтаксиса.

Примечание: будьте осторожны с нарезкой объектов в вашем контейнере.Если вы хотите разрешить хранение базовых и производных классов в контейнере, используйте указатели вместо самих объектов.

2 голосов
/ 21 января 2011

Типовые черты и основанное на политике программирование - это разные темы. Черты типа добавляют новую информацию о существующих типах и типах, которые не могут содержать дополнительную информацию (любую встроенную). Основанное на политике проектирование - это метод проектирования классов, позволяющий собирать их различными способами для создания различных типов поведения; это своего рода шаблон состояния времени компиляции.

...