3

I'm porting a big chunk of code from gcc to Visual Studio 2013. The following code sample works fine (!) on gcc 4.4, but compiling begin() and end() fails on VS2013 with:

error C2440: '' : cannot convert from 'unsigned char *' to '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);
}

Given that I don't want to rewrite the whole thing, is there a portable way to create these const_iterators?

4

2 回答 2

5

没有可移植的方式来做你正在尝试的事情,因为不要求 a(const_)iterator可以从指向基础值类型的指针构造。libstdc++ 恰好提供了这样的构造函数,但 VS 标准库实现却没有。相反,它的(const_)iterator构造函数接受一个指向底层值类型的指针和一个指向容器本身的指针,它用于在调试构建期间执行额外的验证。

最简单的解决方案是替换std::vector<unsigned char>::const_iteratorunsigned 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");

现场演示

于 2014-07-10T16:57:52.023 回答
2

这取决于如何使用begin()end()函数。如果这些函数的调用者实际上期望一个std::vector<unsigned char>::const_iterator(而不是足够通用而不关心确切的类型),那么您必须寻找不同的解决方案。

然后,您可以尝试在其实现中实现变通方法,而不是更改类的接口。value指针有什么用?还有谁可以访问它?如果它是私有成员,则只需将其替换为实际的std::vector<unsigned char>,并使用其data()成员函数 (C++11) 或&value[0](pre C++11) 将指针传递到预期的位置。

于 2014-07-10T17:35:28.930 回答