为什么C 标准库中的集合(std::set
和std::multiset
)提供非const_iterator
方法(set::begin
和multiset::begin
)?
通过迭代器访问键始终是const
。该集合本身是否为const都没关系。为什么要引入那些额外的过载?
请注意,在[Member.Functions]中,它表示为:
对于在C 标准库中描述的非虚拟成员函数,实现可以声明一组不同的成员函数签名,前提文档表现得好像选择了超载。
标准定义了[container.requirements.general]中每个容器的行为,该行为要求:
-
a.begin()
产生iterator
(或常量a
的const_iterator
) -
a.end()
产生iterator
(或a
的const_iterator
) - ...
实现的要求是存在这些类型(C::iterator
和C::const_iterator
),并且这些功能会产生这些类型。要求是不是,具体是必须存在这四个过载(也必须两种迭代器类型必须不同)。要求只是行为。
以下是set
的完美符合实现:
template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>>
class set {
public:
struct iterator { ... };
using const_iterator = iterator;
iterator begin() const { ... };
iterator end() const { ... };
// other stuff
};
通过此实施,满足了所有要求。所以这足够了。确实,这就是LibstDC 实现它的方式 - 两个迭代器是相同的类型,只有一个begin()
,只有一个end()
。
为什么介绍这些额外的过载?
没有额外的超载。或至少不必。这取决于实施者。
虽然我不能肯定地说一致性(请参阅@yurikilochek的评论)对我来说似乎很合理。"如果不存在这些非常规迭代器方法,您能举个一般代码的示例,该代码将失败吗?"以下代码不会使用libstdc 编译(但在Visual Studio下进行编译),因为SET没有非CONST方法。我承认这不是某人在一天进展顺利的过程中会写的代码。
#include <iostream>
#include <vector>
#include <set>
template <class C> //C is some container
void f(C& c)
{
typedef typename C::iterator iter;
typedef iter (C::*fn)(); // note non-const method
fn begin = &C::begin; // will fail with set if begin() is const only
fn end = &C::end;
for (iter i = (c.*begin)(), e = (c.*end)(); i != e; ++i)
std::cout << *i << ' ';
std::cout << 'n';
}
int
main()
{
std::vector<int> v;
std::set<int> s;
f(v);
f(s);
return 0;
}