Классы C++ STLifying

Я пытаюсь записать класс, который содержит несколько станд.:: векторы как элементы данных, и обеспечивают подмножество интерфейса вектора для доступа к ним:

class Mesh
{
public:
private:
  std::vector<Vector3> positions;
  std::vector<Vector3> normals;
  // Several other members along the same lines
};

Главное, которое можно сделать с сеткой, добавляют положения, normals и другой материал к нему. Чтобы позволить подобному STL способу получить доступ к Сетке (добавьте от массивов, других контейнеров, и т.д.), я играю с идеей добавить методы как это:

public:
  template<class InIter>
  void AddNormals(InIter first, InIter last);

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

  1. Это - на самом деле проблема? Моя реакция пищеварительного тракта не состоит в том, чтобы обойти липкие огромные блоки кода в заголовочных файлах, но мой C++ немного ржав с не много опыта STL вне игрушечных примеров, и я не уверен, какая "приемлемая" практика кодирования C++ находится на этом.

  2. Существует ли лучший способ выставить эту функциональность при сохранении подобного STL универсального аромата программирования? Один путь был бы чем-то вроде этого:

(закончите список),

class RestrictedVector<T>
{
public:
  RestrictedVector(std::vector<T> wrapped)
    : wrapped(wrapped) {}

  template <class InIter>
  void Add(InIter first, InIter last)
  {
    std::copy(first, last, std::back_insert_iterator(wrapped));
  }

private:
  std::vector<T> wrapped;
};

и затем выставьте экземпляры их на Сетке вместо этого, но это начинает сильно пахнуть немного сверхразработкой :P Любой совет значительно ценится!

5
задан shambulator 26 May 2010 в 19:53
поделиться

3 ответа

эти методы должны быть определены в файле заголовка

Они должны быть определены в файле заголовка , так что если они используются, то они ' re доступен в единице перевода, в которой создается шаблонная функция. Если вас беспокоит слишком много шаблонов в файлах заголовков, замедляющее компиляцию единиц перевода, которые используют Mesh, но фактически не используют эту функцию шаблона, вы можете переместить реализацию в отдельный файл заголовка. Немного усложняет жизнь клиентам, решая, следует ли включать "жирный" заголовок класса или нет, но на самом деле это несложно.

В качестве альтернативы, для этого конкретного примера вы можете определить итератор вывода для Mesh, который добавляет Normals. Затем клиенты со своими произвольными итераторами могут:

std::copy(first, last, mymesh.normalAdder());

Единственный заголовок, который им нужен с кодом шаблона в нем, - это , который, вполне возможно, у них уже есть.

Чтобы сделать это самостоятельно, объект, возвращаемый normalAdder () , должен перегрузить operator ++ () и operator * () , который сам должен вернуть прокси-объект (обычно * this ), который реализует operator = (const & Vector3) . Это добавляется к вектору нормалей. Но все это не является шаблоном и может быть реализовано в вашем .cpp файле.

В этом примере normalAdder () может просто вернуть std :: back_inserter (this.normals); , шаблон из .

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

5
ответ дан 14 December 2019 в 08:44
поделиться

Я бы сказал, просто прикусите пулю и сделайте чистый, читаемый API / заголовок.

Идея Стива о возврате итератора вывода остроумна, но она будет нелогичной для клиентов вашего класса. Когда кто-то хочет добавить нормали, он будет думать «где же метод добавления нормалей», а не «как мне получить нормальный итератор вывода». (Если только вы не находитесь в очень магазине, поддерживающем STL.)

Требование определения реализации шаблонных методов в заголовке можно несколько смягчить, переместив их за пределы объявления класса.

class Mesh
{
    public:
        void    AddPosition     ( Vector3 const & position );
        void    AddNormal       ( Vector3 const & normal );

        template< typename InIter >
        void    AddPositions    ( InIter const begin, InIter const end );

        template< typename InIter >
        void    AddNormals      ( InIter const begin, InIter const end );

    private:
        std::vector< Vector3 > positions;
        std::vector< Vector3 > normals;
};

template< typename InIter >
void
Mesh::AddPositions< InIter >( InIter const begin, InIter const end )
{
    positions.insert( positions.end(), begin, end );
}

template< typename InIter >
void
Mesh::AddNormals< InIter >( InIter const begin, InIter const end )
{
    normals.insert( normals.end(), begin, end );
}
2
ответ дан 14 December 2019 в 08:44
поделиться
  1. Действительно ли это проблема? Моя интуиция подсказывает, что не стоит засовывать огромные куски кода в заголовочные файлы, но мой C++ немного заржавел. у меня мало опыта работы с STL за пределами игрушечных примеров, и я не уверен, что "приемлемая" практика кодирования на C++ это.

Я бы задал вопрос, нужна ли вам такая универсальность? Помните, что STL был написан, чтобы быть чрезвычайно универсальным для всех. Ваш код предназначен для вас и вашей команды, для решения очень конкретной проблемы. Негенеративный, специфичный для конкретной проблемы интерфейс будет работать отлично и будет более понятен людям из вашей команды/области проблемы.

В противном случае... то, что вы указали, отлично подходит, если вам нужен такой уровень общности. Вы позволили принимать в качестве аргумента любой тип итератора. Нет ничего плохого в том, что у вас есть на первый взгляд. Это может быть очень полезно.

0
ответ дан 14 December 2019 в 08:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: