在 C++ 中重载 *(iterator + n) 和 *(n + iterator)迭代器类?

发布于 2024-08-10 12:02:47 字数 1868 浏览 10 评论 0原文

(注意:我写这个项目只是为了学习;关于它是多余的评论是......呃,多余。;)

我正在尝试实现一个随机访问迭代器,但我发现关于这个主题的文献很少,所以我将通过反复试验并结合维基百科的运算符重载原型列表。 到目前为止,它运行得很好,但我遇到了障碍。

诸如此类的代码可以

exscape::string::iterator i = string_instance.begin();
std::cout << *i << std::endl;

工作,并打印字符串的第一个字符。但是,*(i + 1) 不起作用,*(1 + i) 也不起作用。 我的完整实现显然有点太多了,但要点如下:

namespace exscape {
    class string {
        friend class iterator;
    ...
    public:
        class iterator : public std::iterator<std::random_access_iterator_tag, char> {
            ...
            char &operator*(void) {
                return *p; // After some bounds checking
            }
            char *operator->(void) {
                return p;
            }

            char &operator[](const int offset) {
                return *(p + offset); // After some bounds checking
            }

            iterator &operator+=(const int offset) {
                p += offset;
                return *this;
            }

            const iterator operator+(const int offset) {
                iterator out (*this);
                out += offset;
                return out;
            }

        };
};
}

int main() {
    exscape::string s = "ABCDEF";
    exscape::string::iterator i = s.begin();
    std::cout << *(i + 2) << std::endl;
}

上面的代码失败了(第 632 行当然是 *(i + 2) 行):

string.cpp: In function 'int main( )': string.cpp:632: 错误: '*exscape::string::iterator::operator+(int)(2)' 中的 'operator*' 不匹配 string.cpp:105: 注意:候选者是:char& exscape::string::iterator::operator*()

*(2 + i) 失败并显示:

string.cpp: 在函数 'int main()' 中: string.cpp:632:错误:“2 + i”中的“operator+”不匹配 string.cpp:434: 注意:候选者是: exscape::string exscape::operator+(const char*, const exscape::string&)

我的猜测是我需要做更多的重载,但我不确定什么我失踪了。

(Note: I'm writing this project for learning only; comments about it being redundant are... uh, redundant. ;)

I'm trying to implement a random access iterator, but I've found very little literature on the subject, so I'm going by trial and error combined with Wikpedias list of operator overload prototypes.
It's worked well enough so far, but I've hit a snag.

Code such as

exscape::string::iterator i = string_instance.begin();
std::cout << *i << std::endl;

works, and prints the first character of the string. However, *(i + 1) doesn't work, and neither does *(1 + i).
My full implementation would obviously be a bit too much, but here's the gist of it:

namespace exscape {
    class string {
        friend class iterator;
    ...
    public:
        class iterator : public std::iterator<std::random_access_iterator_tag, char> {
            ...
            char &operator*(void) {
                return *p; // After some bounds checking
            }
            char *operator->(void) {
                return p;
            }

            char &operator[](const int offset) {
                return *(p + offset); // After some bounds checking
            }

            iterator &operator+=(const int offset) {
                p += offset;
                return *this;
            }

            const iterator operator+(const int offset) {
                iterator out (*this);
                out += offset;
                return out;
            }

        };
};
}

int main() {
    exscape::string s = "ABCDEF";
    exscape::string::iterator i = s.begin();
    std::cout << *(i + 2) << std::endl;
}

The above fails with (line 632 is, of course, the *(i + 2) line):

string.cpp: In function ‘int main()’:
string.cpp:632: error: no match for ‘operator*’ in ‘*exscape::string::iterator::operator+(int)(2)’
string.cpp:105: note: candidates are: char& exscape::string::iterator::operator*()

*(2 + i) fails with:

string.cpp: In function ‘int main()’:
string.cpp:632: error: no match for ‘operator+’ in ‘2 + i’
string.cpp:434: note: candidates are: exscape::string exscape::operator+(const char*, const exscape::string&)

My guess is that I need to do some more overloading, but I'm not sure what operator I'm missing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蝶…霜飞 2024-08-17 12:02:47

您的 + 运算符返回一个 const 迭代器,但您没有 const operator*。添加一个,我想你会没事的。或者,正如下面 xtofl 所建议的,您可以将您的 operator* 设置为 const。这是更好的设计,除非您出于某种原因确实需要非常量 operator*

Your + operator returns a const iterator, but you don't have a const operator*. Add one, and I think you'll be all right. Or, as suggested by xtofl below, you can make your operator* const. That's better design, unless you really need the non-const operator* for some reason.

若沐 2024-08-17 12:02:47

首先,您需要一个运算符 *(void) const

[编辑:根据您现有的运算符,应执行以下操作:

char &operator *(void) const {
    // bounds checking
    return *p;
}

]

其次,您需要一个 operator+(int, exscape::string::iterator)。一种相当常见的编写方法是(在迭代器类中):

friend const iterator operator+(const int offset, iterator out) {
    out += offset;
    return out;
}

请注意,将其标记为友元会使其成为非成员函数,即使它是在类内部定义的。您可能还想将 operator+(int) 替换为非成员函数 operator+(iterator,int),以便应用相同的隐式转换规则到 + 的左侧和右侧。

[另一个编辑:正如您在评论中指出的那样,operator+ 无论如何都不应该返回 const iterator - 只需返回 iterator 即可。因此,对于您的代码示例,您实际上不需要 operator*()const。但无论如何你都应该有一个,因为用户可能希望使用类的 const 修改实例来编写代码。]

最后,具有随机访问迭代器(包括 std::string)的标准容器定义一个带符号的 difference_type作为班级的一员。 int 可能不够大,无法包含所有可能的偏移量(例如在 LP64 架构上),但 ptrdiff_t 是一个很好的候选者。

First, you need an operator *(void) const.

[Edit: based on your existing operator, the following should do:

char &operator *(void) const {
    // bounds checking
    return *p;
}

]

Second, you need an operator+(int, exscape::string::iterator). A fairly common way to write this would be (in the iterator class):

friend const iterator operator+(const int offset, iterator out) {
    out += offset;
    return out;
}

Note that marking it friend makes it a non-member function, even though it is defined inside the class. You might also want to replace the operator+(int) with a non-member function, operator+(iterator,int), just so that you get the same implicit conversion rules applied to the LHS and RHS of the +.

[Another edit: as you point out in your comment, operator+ shouldn't be returning const iterator anyway - just return iterator. So for your code example, you don't actually need operator*()const. But you should have one anyway, because users might want to write code using const-modified instances of your class.]

Finally, standard containers with random access iterators (including std::string) define a signed difference_type as a member of the class. int might not be big enough to contain all possible offsets (for example on an LP64 architecture), but ptrdiff_t is a good candidate.

原来是傀儡 2024-08-17 12:02:47

要让它与左侧的数字常量一起使用,您将需要一个非成员函数。像这样的东西(未经测试的代码):

exscape::string::iterator operator+(exscape::string::iterator it, size_t n) {
    return it += n;
}

exscape::string::iterator operator+(size_t n, exscape::string::iterator it) {
    return it += n;
}

To have it work with the numeric constant on the left you will need a non-member function. Something like this (untested code):

exscape::string::iterator operator+(exscape::string::iterator it, size_t n) {
    return it += n;
}

exscape::string::iterator operator+(size_t n, exscape::string::iterator it) {
    return it += n;
}
青瓷清茶倾城歌 2024-08-17 12:02:47

我不相信 *(2 + i) 会起作用,因为左侧操作数需要是您自己的类型。实际上,您是在告诉编译器将迭代器添加到 2,这是没有意义的。 (i + 2) 意味着将我的迭代器向前移动两个索引。

有关详细信息,请参阅 C++ Faq Lite

I don't believe *(2 + i) will work since the left hand operand needs to be your own type. You're actually telling the compiler to add your iterator to 2, which makes no sense. (i + 2) means move my iterator forward two indexes.

See the C++ Faq Lite for more information.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文