STL const_iterator cast — различия в компиляторе

Я портирую большой кусок кода из gcc в Visual Studio 2013. Следующий пример кода работает хорошо (!) На gcc 4.4, но компилируется begin() а также end() не работает на VS2013 с:

ошибка C2440: «»: невозможно преобразовать из «unsigned char *» в «std :: _ Vector_const_iterator >>»

class foo {
unsigned char* value;
int length;

std::vector<unsigned char>::const_iterator begin();
std::vector<unsigned char>::const_iterator end();
};

std::vector<unsigned char>::const_iterator foo::begin() {
return std::vector<unsigned char>::const_iterator(value);
}

std::vector<unsigned char>::const_iterator foo::end() {
return std::vector<unsigned char>::const_iterator(value + length);
}

Учитывая, что я не хочу переписывать все это, есть ли портативный способ создания этих const_iterators?

3

Решение

Нет портативного способа сделать то, что вы пытаетесь, потому что нет требования, чтобы (const_)iterator быть конструируемым из указателя на базовый тип значения. libstdc ++ предоставляет такой конструктор, но реализация стандартной библиотеки VS этого не делает. Вместо этого его (const_)iterator Конструктор получает указатель на базовый тип значения и указатель на сам контейнер, который он использует для выполнения дополнительной проверки во время отладочных сборок.

Самое простое решение — заменить std::vector<unsigned char>::const_iterator с unsigned char const *, Необработанный указатель попадает в категорию RandomAccessIterator, которая совпадает с vector::(const_)iterators.

unsigned char const *foo::begin() {
return value;
}

unsigned char const *foo::end() {
return value + length;
}

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

#include <boost/iterator/iterator_facade.hpp>

struct const_foo_iterator : boost::iterator_facade<const_foo_iterator,
unsigned char const,
boost::random_access_traversal_tag>
{
const_foo_iterator() = default;
const_foo_iterator(unsigned char const *iter) : iter(iter) {}
private:
friend class boost::iterator_core_access;

void increment() { ++iter; }
void decrement() { --iter; }
void advance(std::ptrdiff_t n) { iter += n; }

std::ptrdiff_t distance_to(const_foo_iterator const& other) const
{ return iter - other.iter; }

bool equal(const_foo_iterator const& other) const
{ return this->iter == other.iter; }

unsigned char const& dereference() const { return *iter; }
unsigned char const* iter = nullptr;
};

const_foo_iterator foo::begin() {
return value;
}

const_foo_iterator foo::end() {
return value + length;
}

static_assert(std::is_same<std::iterator_traits<const_foo_iterator>::value_type,
unsigned char>::value, "value_type");
static_assert(std::is_same<std::iterator_traits<const_foo_iterator>::pointer,
unsigned char const *>::value, "pointer");
static_assert(std::is_same<std::iterator_traits<const_foo_iterator>::iterator_category,
std::random_access_iterator_tag>::value, "iterator_category");

Живая демо

5

Другие решения

Это зависит от того, как begin() а также end() функции используются. Если вызывающие эти функции действительно ожидают std::vector<unsigned char>::const_iterator (вместо того, чтобы быть достаточно общим, чтобы не заботиться о точном типе), вам придется искать различные решения.

Вместо того, чтобы менять интерфейс класса, вы можете попытаться применить обходной путь в его реализации. Что такое value указатель нужен для? Кто еще имеет к нему доступ? Если это частный участник, то просто замените его фактическим std::vector<unsigned char>и использовать его data() функция-член (C ++ 11) или &value[0] (до C ++ 11) для передачи указателя туда, где он ожидается.

2

По вопросам рекламы [email protected]