1

Я пытаюсь создать небольшой класс-оболочку вокруг std :: vector, чтобы представить коэффициенты многочлена. Вызывающий должен иметь возможность выполнять итерацию через коэффициенты, но я не хочу раскрывать основную реализацию.Компилятор не может «преобразовать» между Vector_const_iterator и Vector_iterator, хотя методы для обоих доступны

Используя шаблон описал here, here, и в других местах, я попытался пройти по итераторы, как показано ниже:

typedef std::vector<unsigned char> charVec; 

class gf255_poly 
{ 
    public: 

     // Constructors and Polynomial-y Functions 

     // ... 

     // Iterators to go from high to low degree 

     charVec::const_reverse_iterator h2l_begin() const { return p.rbegin(); }; 
     charVec::const_reverse_iterator h2l_end() const { return p.rend(); }; 
     charVec::reverse_iterator  h2l_begin() { return p.rbegin(); }; 
     charVec::reverse_iterator  h2l_end() { return p.rend(); }; 

     // Iterators to go from low to high degree 

     charVec::const_iterator l2h_begin() const { return p.begin(); }; 
     charVec::const_iterator l2h_end() const { return p.end(); }; 
     charVec::iterator  l2h_begin() { return p.begin(); }; 
     charVec::iterator  l2h_end() { return p.end(); }; 

    protected: 
     std::vector<unsigned char> p; 
}; 

Эти gf255_poly объекты затем привыкают в таких методов, как это:

// Performs polynomial evaluation in GF(2^8) 
unsigned char gf255_poly_eval(const gf255_poly &poly, unsigned char x) const 
{ 
    unsigned char fx = poly.coefHigh(); // Initialize with coef of highest degree term 

    // Use Horner's method with consecutively factored terms: 
    // x^3 + 2x^2 + 3x + 4 -> (((1x + 2)x + 3)x + 4) 

    charVec::reverse_iterator next_coef; 

    for (next_coef = poly.h2l_begin(); next_coef != poly.h2l_end(); next_coef++) 
     fx = gf255_mul(fx, x)^*next_coef; // Recall^is addition in GF 2^8 

    return fx; 
} 

Простой, хотя кажется, что что-то не так с типами. Visual Studio дает мне эту ошибку на линии с для цикла, который я не могу разобраться:

error C2664: 'std::_Revranit<_RanIt,_Base>::_Revranit(_RanIt)' : cannot convert parameter 1 from 'std::_Vector_const_iterator<_Ty,_Alloc>' to 'std::_Vector_iterator<_Ty,_Alloc>' 

Я не понимаю, это сообщение - я предоставил методы, которые возвращают как итераторы и const_iterators. Почему компилятор не может выбирать между ними?


Неявные в этом вопросе, является ли это хорошая стратегия для сокрытия деталей от вызывающей вообще (так как они по-прежнему приходится иметь дело с этими StD :: типов векторных), и я был бы признателен за ответы, также обратитесь к этому.

ответ

1
charVec::reverse_iterator next_coef = poly.h2l_begin(); 

next_coef является reverse_iterator. Что возвращает h2l_begin()?

Ну poly является:

const gf255_poly &poly 

const gf255_poly. Итак, давайте посмотрим на переопределениях h2l_begin():

charVec::const_reverse_iterator h2l_begin() const { return p.rbegin(); }; 
charVec::reverse_iterator  h2l_begin() { return p.rbegin(); }; 

Есть два перегрузок. Только один справедливо, потому что poly является const, и что это одна:

charVec::const_reverse_iterator h2l_begin() const { return p.rbegin(); }; 

так poly.h2l_begin() возвращает charVec::const_reverse_iterator.

charVec::const_reverse_iterator не может быть преобразован в charVec::reverse_iterator, потому что charVec::const_reverse_iterator позволяет изменять вещь итерируемым над, а charVec::reverse_iterator нет.

Одним словом, поскольку poly является const, вы пообещали не изменять его. И затем вы повторили его, используя типы, которые могли бы изменить его. Таким образом, вы получаете ошибку типа.

Во-вторых, и в качестве примечания обратите внимание, что компилятор никогда не выбирает между функциями на основе типа возврата (за исключением, возможно, преобразования operator T()). Если у вас был неконстантный poly, он сохранил его в const_reverse_iterator, вы все равно вызывают reverse_iterator h2l_begin(). reverse_iterator просто преобразуется в const_reverse_iterator.


Первое, что нужно сделать, это перейти на C++ 11. Это 2016.

Во-вторых, я бы написать range_t<Iterator>, который хранит диапазон итераторов и выставляет begin и end и условно (на основе случайного доступа-ности Iteratoroperator[], size и т.д. Также remove_front(size_t) и front() и empty и ...

Тогда я написать array_view<T>:range_it<T*>, которая представляет собой ряд смежных с T, с неявных ctors из контейнеров с методом T* C::data(), сырым C-массивами и T*, size_t.

Наконец, я бы написал backwards_t и backwards функции, которая принимает range_t<Iterator> и возвращает range_t< reverse_iterator<Iterator> >.

Теперь мой gf255_poly имеет следующие:

backwards_t< array_view< unsigned char > > h2l(); 
backwards_t< array_view< unsigned char const > > h2l() const; 
array_view< unsigned char > l2h(); 
array_view< unsigned char const > l2h() const; 

Мы можем выставить для определений типов итераторов, если мы выбираем (и в C++ 03 есть небольшой выбор).

В C++ 11 он выглядит следующим образом:

for (auto&& next_coef = poly.h2l()) 
    fx = gf255_mul(fx, x)^next_coef; // Recall^is addition in GF 2^8 

что приятно.

+0

К сожалению, C++ 11 ISN» t в настоящее время вариант. Весь магазин dev живет в надежде на обновление до VS, но нет никаких признаков того, что это произойдет. Тем не менее, спасибо за тщательный ответ и больше боеприпасов, чтобы продвигать новые функции! – Bear

1

poly - объект const, поэтому h2l_begin() вернет const_reverse_iterator. Вы объявили next_coef как reverse_iterator, и вы не можете назначить итератор const для итератора. Либо изменение next_coef должно быть const_reverse_iterator, либо объявить его в цикле for с авто.

for (auto next_coef = poly.h2l_begin(); next_coef != poly.h2l_end(); ++next_coef) 
0

Изменить это:

charVec::reverse_iterator next_coef; 

к этому:

charVec::const_reverse_iterator next_coef; 

Вы видите: poly является const ссылкой на gf255_poly объект, то есть запрос на poly.h2l_begin(); предпочтет const квалифицированной версию, что функция во время разрешения перегрузки.

еще лучше, использовать auto

for (auto next_coef = poly.h2l_begin(); next_coef != poly.h2l_end(); next_coef++) 
    fx = gf255_mul(fx, x)^*next_coef; // Recall^is addition in GF 2^8 

Если вы все еще должны держать итератор вне для контура инициализаторе, вы можете перемещать intitialization снаружи:

auto next_coef = poly.h2l_begin() 
for (; next_coef != poly.h2l_end(); next_coef++) 
    fx = gf255_mul(fx, x)^*next_coef; // Recall^is addition in GF 2^8