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);
会导致错误,但不会。这是否意味着这三个实现对两个迭代器都使用相同的类型?
但是即使在那种情况下,即使我找到了一个对于这些迭代器都不使用相同类型的编译器,我仍然不明白为什么会发生ODR违规。如果类型不同,则禁止的转换(从const到非const)应该触发错误,但这与ODR无关。谁能给我举个例子说明该违规行为,或解释该注释的含义?
答案 0 :(得分:8)
有两个也许:
如果别名类型相同,则表示违反了ODR,与此相同:
using type_1 = int;
using type_2 = int;
void func(type_1) {}
void func(type_2) {}
在签名中考虑别名类型,而不是可以为每种类型创建的任意数量的别名。上面两个定义的签名是相同的。
答案 1 :(得分:8)
您必须以相同的方式命名函数以获取错误。更改的代码:https://rextester.com/SSNZ54459
错误是
source_file.cpp: In function ‘void print_set_iter(std::set<int>::const_iterator&)’:
source_file.cpp:8:6: error: redefinition of ‘void print_set_iter(std::set<int>::const_iterator&)’
void print_set_iter(std::set<int>::const_iterator& const_it) {
^
source_file.cpp:4:6: note: ‘void print_set_iter(std::set<int>::iterator&)’ previously defined here
void print_set_iter(std::set<int>::iterator& it) {
^