【问题标题】:how to implicitly convert a foo<const bar> into a const foo<bar> in C++ template?如何在 C++ 模板中将 foo<const bar> 隐式转换为 const foo<bar>?
【发布时间】:2022-01-12 22:05:54
【问题描述】:

我正在制作我自己的矢量容器,并且我正在尝试使用 C++98 标准实现一个像真实的迭代器一样工作的迭代器。

这是作业,所以我不希望答案只是提示我应该看哪里以及应该学习什么才能解决这个问题。

所以基本上我正在尝试使这段代码工作:

ft::vector<int> v (100, 100);
ft::vector<int>::iterator it = v.begin();
ft::vector<int>::const_iterator cit = it;

std::cout << (cit == it) << std::endl; //comparison 1 /// works
std::cout << (it == cit) << std::endl; //comparison 2 /// doesn't compile
std::cout << (cit + 1 == it + 1) << std::endl; //doesn't work
std::cout << (it + 1 == cit + 1) << std::endl; //doesn't work

iteratorconst_iterator 是这样的类型定义:

typedef typename ft::iterator_vector<value_type> iterator;
typedef typename ft::iterator_vector<const value_type> const_iterator;

值类型是传递给向量模板的类型。

直到我在迭代器模板中添加一个用户定义的转换运算符以将 iterator&lt;const foo&gt; 转换为 iterator&lt;foo&gt; 之前,第一次比较不起作用(实际上正如 @ 所指出的那样特德林莫) 这是operator iterator_vector&lt;const value_type&gt;() const { return _p; } 但是编译器说我现在需要能够将iterator&lt;const foo&gt; 转换为const iterator&lt;foo&gt;,我不知道如何继续。

这是我的迭代器的实现:

template <class T>
class iterator_vector : public ft::iterator<std::random_access_iterator_tag, T> {

public:

    typedef             ft::iterator<std::random_access_iterator_tag, T>    iterator;
    typedef             ft::iterator_traits<iterator>                   iterator_traits;
    typedef typename    iterator_traits::difference_type                difference_type;
    typedef typename    iterator_traits::value_type                     value_type;
    typedef typename    iterator_traits::pointer                        pointer;
    typedef typename    iterator_traits::reference                      reference;
    typedef typename    iterator_traits::iterator_category              iterator_category;

    /*
    ** Member functions
    */

    iterator_vector(pointer p = 0) : _p(p) {}
    ~iterator_vector(void) {}

    operator iterator_vector<const value_type>() const { return _p; }

    iterator_vector& operator++() { ++_p; return *this; }
    iterator_vector operator++(int)
    {
        iterator_vector r = *this;
        ++_p;
        return r;
    }
    iterator_vector& operator--() { --_p; return *this; }
    iterator_vector operator--(int)
    {
        iterator_vector r = *this;
        --_p;
        return r;
    }
    iterator_vector operator+(size_t n) const { return iterator_vector(_p + n); }
    iterator_vector operator-(size_t n) const { return iterator_vector(_p - n); }
    iterator_vector& operator+=(size_t n) { _p += n; return *this; }
    iterator_vector& operator-=(size_t n) { _p -= n; return *this; }
    difference_type operator+(iterator_vector rhs) const { return _p + rhs._p; }
    difference_type operator-(iterator_vector rhs) const { return _p - rhs._p; }
    reference operator*(void) const { return *_p; }
    pointer operator->() const { return _p; }
    reference operator[](size_t n) const { return _p[n]; }
    bool operator==(const iterator_vector& rhs) const { return _p == rhs._p; }
    bool operator!=(const iterator_vector& rhs) const { return _p != rhs._p; }
    bool operator<(const iterator_vector& rhs) const { return _p > rhs._p; }
    bool operator>(const iterator_vector& rhs) const { return _p < rhs._p; }
    bool operator<=(const iterator_vector& rhs) const { return _p <= rhs._p; }
    bool operator>=(const iterator_vector& rhs) const { return _p >= rhs._p; }

    /*
    ** Non-member functions
    */

    friend iterator_vector operator+(size_t n, const iterator_vector& rhs) { return iterator_vector(rhs._p + n); }
    friend iterator_vector operator-(size_t n, const iterator_vector& rhs) { return iterator_vector(rhs._p - n); }

private:

    pointer _p;

};

【问题讨论】:

  • 通常你会有一个“iterator”和一个“const_iterator”。在这里查看en.cppreference.com/w/cpp/container/vector
  • @Jellyboy 你是什么意思?我已经有一个 const_iterator 了。我使用我的迭代器模板,但使用 iterator 而不是 iterator。你的意思是我应该有两个单独的类模板而不是重用相同的迭代器模板?
  • @tvanbesi 不,如果您制作基于模板的迭代器,您很可能不应该有两个单独的模板。
  • 您不想要这种转换。你真的不知道。想象一下如果const char* 可以隐式转换为char * const 会发生什么。迭代器是花哨的指针,应该像指针一样工作。
  • @n.1.8e9-where's-my-sharem。我也对此做出了反应。我更新了我的答案来解决这个问题。

标签: c++ templates compiler-errors c++98 qualifiers


【解决方案1】:

从代码中的 cmets 看来,当iterator 位于左侧且const_iterator 位于右侧时,您缺少比较函数的失败原因。您可以添加这个免费功能:

template<typename T>
bool operator==(const iterator_vector<T>& lhs, const iterator_vector<const T>& rhs) {
    // just swap the order here and the implicit conversion from `iterator`
    // to `const_iterator` from `lhs` solves the rest:
    return rhs == lhs;
}

我在我的迭代器模板中添加了一个用户定义的转换运算符来将iterator&lt;const foo&gt; 转换为iterator&lt;foo&gt;

不,您以相反的方式添加了隐式转换。也就是说,从iteratorconst_iterator - 这很好!


另一种方法是使两个迭代器 friends 不必为所有运算符实现类似的交换 lhsrhs 函数。然后,模板中的运算符将变为:

// define these before your class template (borrowed from C++11):
template< class T > struct remove_const          { typedef T type; };
template< class T > struct remove_const<const T> { typedef T type; };
//... in your class template:
friend class iterator_vector<typename remove_const<T>::type>;
friend class iterator_vector<const T>;

template<typename U>
bool operator==(const iterator_vector<U>& rhs) const { return _p == rhs._p; }
template<typename U>
bool operator!=(const iterator_vector<U>& rhs) const { return _p != rhs._p; }
template<typename U>
bool operator<(const iterator_vector<U>& rhs) const { return _p > rhs._p; }
template<typename U>
bool operator>(const iterator_vector<U>& rhs) const { return _p < rhs._p; }
template<typename U>
bool operator<=(const iterator_vector<U>& rhs) const { return _p <= rhs._p; }
template<typename U>
bool operator>=(const iterator_vector<U>& rhs) const { return _p >= rhs._p; }

【讨论】:

  • 所有其他比较运算符呢? OP是否也需要添加它们?
  • @n.1.8e9-where's-my-sharem。是的,OP 需要为所有操作员交换功能。我添加了一个替代方案。
  • @tvanbesi 只需添加remove_const 我在答案中的定义。它们与 C++98 兼容。它们不是您在以后的 C++ 标准中包含 &lt;type_traits&gt; 时得到的 std::remove_const。如果需要,您可以将它们放在您的 ft 命名空间中。
  • @TedLyngmo 完美 :)
  • 如果您不小心比较了两个不相关的迭代器,则错误消息可能相当神秘。你可以用这种方式“修复”它(某种程度上)godbolt.org/z/1KK6TjqTo,即使它可能有点矫枉过正。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-13
  • 2011-01-18
  • 1970-01-01
  • 2020-02-02
  • 2022-11-04
  • 1970-01-01
相关资源
最近更新 更多