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

STL const_iterator cast -- compiler differences

本文关键字:编译器 转换 const iterator STL      更新时间:2023-10-16

我正在将一大块代码从gcc移植到Visual Studio 2013。下面的代码示例在gcc 4.4上运行良好(!),但是在VS2013上编译begin()end()失败:

错误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_iterator ?

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

最简单的解决方案是用unsigned char const *代替std::vector<unsigned char>::const_iterator。原始指针属于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");

现场演示

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

与其更改类的接口,不如尝试在其实现中实现一个变通方法。value指针需要做什么?还有谁有权限?如果它是私有成员,那么只需将其替换为实际的std::vector<unsigned char>,并使用其data()成员函数(c++ 11)或&value[0] (c++ 11之前)来传递期望的指针。