#c #boost #iterator #operator-overloading #stdvector
#c #повышение #итератор #оператор-перегрузка #stdvector
Вопрос:
Я начал писать класс, который действовал бы очень похоже на std::vector
, но с некоторыми математическими операциями. В основном такие вещи, как норма вектора и перегрузка важных математических операторов ( ,- и т.д.), Которые будут добавлять или вычитать элементы поэлементно.
Класс размещен ниже, я использовал boost::operators
для написания всех математических операторов, и все они работают безупречно. Я столкнулся с некоторыми проблемами при реализации итератора. Я попытался написать итератор как вложенный класс и использовать boost::iterator
для получения большей части / всей функциональности std::vector
итератора.
Здесь я столкнулся с проблемой, код не будет компилироваться с выводом ошибок, связанных с шаблоном, примерно на 2 мили. Который я могу опубликовать, если вам интересно, но это типичные подробные ошибки шаблона boost.
Мой вопрос двоякий.
Во-первых, является ли композиция лучшим выбором дизайна? Что я мог бы сделать лучше с частным наследованием или шаблоном декоратора? Или, может быть, кто-нибудь знает о реализации этой идеи в библиотеке?
Во-вторых, что я делаю не так с итератором? Я чувствую, что мне не хватает чего-то фундаментального в моей boost::iterator
реализации, и я хотел бы это исправить, а не менять свой дизайн.
Я не включил реализацию в большинство методов, поскольку они либо тривиальны, либо неважны.
//publicly inherits important boost::operators classes
template <class T>
class Coords: boost::arithmetic<Coords<T>
,boost::arithmetic<Coords<T>, T
// ,boost::indexable<Coords<T>,int,Tamp;
// ,boost::dereferenceable<Coords<T>, T*>
// >
>
>
{
private:
//private member
std::vector<T> x_;
public:
//public constructors
Coords(int n, T x): x_(n,x){};
Coords(int n): x_(n){};
Coords(std::vector<T> amp;x);
Coords(const Coords amp;rhs);
//iterator nested class, public inherits boost::iterator_facade
class iterator: public boost::iterator_facade<iterator, Coords<T>, std::random_access_iterator_tag>{
private:
typename std::vector<T>::iterator iter_;
friend class boost::iterator_core_access;
void increment() { iter_ = iter_ ;};
void decrement() { iter_ = iter_--;};
void advance(int n){ iter_ = iter_ =n;};
void equal(iterator const amp;other) const{
return this->iter_ == other.iter_;
}
Tamp; dereference() const {return *iter_;};
int distance_to(iterator const amp;other) const{
return this->iter_ - other.iter_;
}
public:
iterator():iter_(0){};
explicit iterator(const typename Coords<T>::iteratoramp; it):iter_(it.iter_){};
explicit iterator(const typename std::vector<T>::iteratoramp; it):iter_(it){};
};
//methods from std::vector I would like to 'copy'
typename Coords<T>::iterator begin(){return iterator(x_.begin());};
typename Coords<T>::iterator end(){return iterator(x_.end());};
typename Coords<T>::iterator operator[](std::size_t n);
std::size_t size(){return x.size()};
//mathematical methods
T norm() const;
T square() const;
T sum() const;
T dotProd(const Coords amp;rhs);
//important operator overloads
Coords operator =(const T amp;rhs);
Coords operator-=(const T amp;rhs);
Coords operator*=(const T amp;rhs);
Coords operator/=(const T amp;rhs);
Coords operator =(const Coords<T> amp;rhs);
Coords operator-=(const Coords<T> amp;rhs);
Coords operator*=(const Coords<T> amp;rhs);
Coords operator/=(const Coords<T> amp;rhs);
};
Комментарии:
1. Я предполагаю, что вы создаете этот класс в качестве личного упражнения. Если вы действительно хотите использовать математическую библиотеку, попробуйте Blitz .
2. @chris Blitz давно мертв. Это ublas, или собственный, или armadillo.
3. @Anycorn Да, я только что понял, что они не обновлялись очень долгое время. Да здравствует uBLAS!
4. Вы уверены, что вам действительно нужно внедрять свои собственные итераторы? Разве
typedef typename std::vector<T>::iterator iterator;
недостаточно хорошо?5. Он начинался как класс quick container и вырос в вышеупомянутый. Я отказался от него в пользу uBLAS, но мне все еще интересно узнать о boost :: iterator и моей реализации.
Ответ №1:
Это устраняет ряд проблем с программой:
#include <boost/operators.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <vector>
//publicly inherits important boost::operators classes
template <class T>
class Coords: boost::arithmetic<Coords<T>
,boost::arithmetic<Coords<T>, T
// ,boost::indexable<Coords<T>,int,Tamp;
// ,boost::dereferenceable<Coords<T>, T*>
// >
>
>
{
private:
//private member
std::vector<T> x_;
public:
//public constructors
Coords(int n, T x): x_(n,x){};
Coords(int n): x_(n){};
Coords(std::vector<T> amp;x);
Coords(const Coords amp;rhs);
//iterator nested class, public inherits boost::iterator_facade
class iterator: public boost::iterator_facade<iterator, T, boost::random_access_traversal_tag >{
private:
typename std::vector<T>::iterator iter_;
friend class boost::iterator_core_access;
void increment() { iter_;}
void decrement() { --iter_; }
void advance(int n){ iter_ =n;};
bool equal(iterator const amp;other) const{
return this->iter_ == other.iter_;
}
Tamp; dereference() const {return *iter_;};
int distance_to(iterator const amp;other) const{
return this->iter_ - other.iter_;
}
public:
iterator():iter_(0){};
iterator(const iteratoramp; it):iter_(it.iter_){};
iterator(iteratoramp; it):iter_(it.iter_){};
explicit iterator(const typename std::vector<T>::iteratoramp; it):iter_(it){};
};
//methods from std::vector I would like to 'copy'
iterator begin(){return iterator(x_.begin());};
iterator end(){return iterator(x_.end());};
iterator operator[](std::size_t n);
std::size_t size(){return x_.size();};
//mathematical methods
T norm() const;
T square() const;
T sum() const;
T dotProd(const Coords amp;rhs);
//important operator overloads
Coords operator =(const T amp;rhs);
Coords operator-=(const T amp;rhs);
Coords operator*=(const T amp;rhs);
Coords operator/=(const T amp;rhs);
Coords operator =(const Coords<T> amp;rhs);
Coords operator-=(const Coords<T> amp;rhs);
Coords operator*=(const Coords<T> amp;rhs);
Coords operator/=(const Coords<T> amp;rhs);
};
int main() {
Coords<int> c(3);
for(Coords<int>::iterator it(c.begin()); it != c.end(); it)
*it;
}
- В документации Boost, кажется, говорится, что третий параметр шаблона для
iterator_facade
являетсяboost::
тегом, а неstd::
меткой. - Вторым параметром шаблона для
iterator_facade
является тип значения, а не тип контейнера. - Код для
increment
,decrement
иadvance
всего созданного (я думаю) неопределенного поведения. - При обращении к членам класса изнутри определения класса вам не нужно указывать имя класса. Было несколько мест,
Coords<T>::
которые пришлось удалить.
Комментарии:
1. Я согласен с вашим первым пунктом, хотя я нигде не могу найти
boost::
тег. Я, честно говоря, не знаю, о чем я думал, когда писал increment, decrement, advance. Должно быть, кофе было мало. Основными проблемами с моим исходным кодом, которые я не понял, были 1) второй параметр шаблона и явное указание конструктора копирования. Другие проблемы были простыми. Большое спасибо!