简体   繁体   English

STL const_iterator强制转换 - 编译器差异

[英]STL const_iterator cast — compiler differences

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: 我正在将一大块代码从gcc移植到Visual Studio 2013.以下代码示例在gcc 4.4上工作正常(!),但编译begin()end()在VS2013上失败:

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

Given that I don't want to rewrite the whole thing, is there a portable way to create these const_iterators? 鉴于我不想重写整个事物,是否有可行的方法来创建这些const_iterators?

There is no portable way to do what you're attempting because there is no requirement that a (const_)iterator be constructible from a pointer to the underlying value type. 没有可移植的方法来执行您正在尝试的操作,因为不需要(const_)iterator可以从指向底层值类型的指针构造。 libstdc++ happens to provide such a constructor but the VS standard library implementation doesn't. libstdc ++恰好提供了这样的构造函数,但VS标准库实现却没有。 Instead, its (const_)iterator constructor takes a pointer to the underlying value type and a pointer to the container itself, which it uses to perform additional validation during debug builds. 相反,它的(const_)iterator构造函数接受一个指向底层值类型的指针和一个指向容器本身的指针,它用于在调试版本中执行其他验证。

The easiest solution is to replace std::vector<unsigned char>::const_iterator with unsigned char const * . 最简单的解决方案是用unsigned char const *替换std::vector<unsigned char>::const_iterator A raw pointer falls in the RandomAccessIterator category, which is the same as vector::(const_)iterator s. 原始指针属于RandomAccessIterator类别,与vector::(const_)iterator s相同。

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

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

If you needs the iterator to be a class type, then you'll need to create a custom iterator. 如果您需要将迭代器作为类类型,那么您将需要创建自定义迭代器。 While this can be done from scratch, it's a lot easier to use Boost.IteratorFacade , which will provide a bunch of the necessary boilerplate that goes into constructing a custom iterator. 虽然这可以从头开始,但使用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");

Live demo 现场演示

It depends on how the begin() and end() functions are used. 这取决于如何使用begin()end()函数。 If the callers of those functions actually expect a std::vector<unsigned char>::const_iterator (rather than being generic enough not to care about the exact type), then you have to search for different solutions. 如果这些函数的调用者实际上期望一个std::vector<unsigned char>::const_iterator (而不是足够通用而不关心确切的类型),那么你必须搜索不同的解决方案。

Rather than changing the interface of the class, you could then try to implement a workaround in its implementation. 您可以尝试在其实现中实现变通方法,而不是更改类的接口。 What's the value pointer needed for? 需要什么value指针? Who else has access to it? 还有谁可以访问它? If it's a private member, then just replace it with an actual std::vector<unsigned char> , and use its data() member function (C++11) or &value[0] (pre C++11) to pass a pointer where one is expected. 如果它是私有成员,那么只需用实际的std::vector<unsigned char>替换它,并使用其data()成员函数(C ++ 11)或&value[0] (pre C ++ 11)来传递它一个预期的指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM