【发布时间】:2019-11-04 04:02:41
【问题描述】:
std::set 容器 given by cppreference.com 的描述在末尾包含此注释:
成员类型
iterator和const_iterator可能是同一类型的别名。由于iterator可转换为const_iterator,因此应在函数参数列表中使用const_iterator,以避免违反单一定义规则。
我不明白最后这句话。我的理解是一个集合不允许修改它的元素(如果你需要改变一个,你必须erase它然后insert新的),所以每个iterator都可以作为const_iterator .该标准补充说,它们有可能(但不是必需的)是同一类型。到目前为止,一切都很清楚。
我没有得到的是可能违反One Definition Rule。这条规则说一个函数可以有很多声明,但只有一个定义。怎么违反了?假设我有一个set<int>,我创建了一个以迭代器为参数的函数。由于它们的工作方式相同,我可以选择它的类型:set<int>::iterator 或 set<int>::const_iterator。如果我不遵循建议,即选择set<int>::iterator,会发生什么?
我编写了一个程序来尝试找到答案。基本上有2个函数,一个接受iterator,另一个接受const_iterator,我调用它们每个两次,一次通过iterator,一次通过const_iterator。这里是:
#include <iostream>
#include <set>
void print_set_iter(std::set<int>::iterator& it) {
std::cout << "Set element from iterator: " << *it << "\n";
}
void print_set_const_iter(std::set<int>::const_iterator& const_it) {
std::cout << "Set element from const_iterator: " << *const_it << "\n";
}
int main() {
std::set<int> primes = {2, 3, 5, 7, 11};
std::set<int>::iterator it = primes.find(3);
std::set<int>::const_iterator const_it = primes.find(5);
print_set_iter(it);
print_set_iter(const_it);
print_set_const_iter(it);
print_set_const_iter(const_it);
}
我已经在rextester.com 上使用 3 个最流行的编译器(gcc、clang、MSVC)编译了这个:没有警告,并且运行良好。通常我希望print_set_iter(const_it); 会导致错误,但事实并非如此。这是否意味着这 3 个实现对两个迭代器使用相同的类型?
但即使在那种情况下,即使我找到了一个不为这些迭代器使用相同类型的编译器,我仍然不明白为什么会出现 ODR 违规。如果类型不同,则禁止转换(从 const 到非 const)应该会触发错误,但这与 ODR 无关。谁能给我看一个违规的例子,或者解释一下这个注释是什么意思?
【问题讨论】:
-
我想我目前没有编辑 cppreference.com 的权限,但我提出了更改建议:en.cppreference.com/w/Talk:Main_Page/…
-
@aschepler 太好了,我不知道可以建议对 cppreference.com 进行编辑!我仍在研究这个问题(好吧,我今天被打断了......)但我可以说这里的答案帮助我澄清了情况,我意识到我走上了完全错误的轨道,至少在我责怪他们措辞的方式。谢谢你,我真的很感激!
标签: c++ iterator set parameter-passing one-definition-rule